diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index 8569df17..f2d10d2a 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -357,6 +357,39 @@ RPiCameraConfiguration::RPiCameraConfiguration(const RPiCameraData *data)
 {
 }
 
+static const std::vector<ColorSpace> validColorSpaces = {
+	ColorSpace::Sycc,
+	ColorSpace::Smpte170m,
+	ColorSpace::Rec709
+};
+
+static std::optional<ColorSpace> fixColorSpace(const std::optional<ColorSpace> &colorSpace,
+					       CameraConfiguration::Status &status)
+{
+	if (!colorSpace)
+		return std::nullopt;
+
+	/*
+	 * We prefer to restore any YCbCr encoding and range information that may have been
+	 * removed from RGB streams. This ensures the colour spaces will be converted correctly
+	 * into the colour spaces that the drivers handle, namely V4L2_COLORSPACE_JPEG,
+	 * V4L2_COLORSPACE_SMPTE170M and V4L2_COLORSPACE_REC709.
+	 *
+	 * Luckily, the primaries and transfer function are enough for us to deduce exactly which
+	 * ColorSpace was originally intended.
+	 */
+	for (const auto &cs : validColorSpaces) {
+		if (colorSpace->primaries == cs.primaries &&
+		    colorSpace->transferFunction == cs.transferFunction)
+			return cs;
+	}
+
+	/* If nothing was matched, ask for sYCC. */
+	LOG(RPI, Debug) << "No match for colour space " << colorSpace->toString();
+	status = CameraConfiguration::Adjusted;
+	return ColorSpace::Sycc;
+}
+
 CameraConfiguration::Status RPiCameraConfiguration::validate()
 {
 	Status status = Valid;
@@ -533,7 +566,26 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
 		V4L2DeviceFormat format;
 		format.fourcc = dev->toV4L2PixelFormat(cfg.pixelFormat);
 		format.size = cfg.size;
-		format.colorSpace = cfg.colorSpace;
+		/*
+		 * Make sure the colour space is the one we want converted for our drivers, with
+		 * the YCbCr information restored. status will be set to Adjusted if we didn't
+		 * like the input colour space.
+		 */
+		format.colorSpace = fixColorSpace(cfg.colorSpace, status);
+
+		/*
+		 * When it comes back, RGB streams will have had the YCbCr information
+		 * overwritten again, so let's figure out what we really expect to be
+		 * returned.
+		 */
+		auto checkColorSpace = format.colorSpace;
+		if (checkColorSpace) {
+			const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
+			if (info.colourEncoding == PixelFormatInfo::ColourEncodingRGB) {
+				checkColorSpace->ycbcrEncoding = ColorSpace::YcbcrEncoding::None;
+				checkColorSpace->range = ColorSpace::Range::Full;
+			}
+		}
 
 		LOG(RPI, Debug)
 			<< "Try color space " << ColorSpace::toString(cfg.colorSpace);
@@ -542,7 +594,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
 		if (ret)
 			return Invalid;
 
-		if (cfg.colorSpace != format.colorSpace) {
+		if (checkColorSpace != format.colorSpace) {
 			status = Adjusted;
 			LOG(RPI, Debug)
 				<< "Color space changed from "
