diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h
index a7759ccb..32a7f812 100644
--- a/include/libcamera/camera.h
+++ b/include/libcamera/camera.h
@@ -69,6 +69,8 @@ public:
 protected:
 	CameraConfiguration();
 
+	Status validateColorSpaces(bool sharedColorSpace);
+
 	std::vector<StreamConfiguration> config_;
 };
 
diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
index 400a7cf0..dd06f600 100644
--- a/src/libcamera/camera.cpp
+++ b/src/libcamera/camera.cpp
@@ -20,6 +20,7 @@
 
 #include "libcamera/internal/camera.h"
 #include "libcamera/internal/camera_controls.h"
+#include "libcamera/internal/formats.h"
 #include "libcamera/internal/pipeline_handler.h"
 
 /**
@@ -314,6 +315,43 @@ std::size_t CameraConfiguration::size() const
 	return config_.size();
 }
 
+static bool isRaw(const PixelFormat &pixFmt)
+{
+	const PixelFormatInfo &info = PixelFormatInfo::info(pixFmt);
+	return info.isValid() &&
+	       info.colourEncoding == PixelFormatInfo::ColourEncodingRAW;
+}
+
+CameraConfiguration::Status CameraConfiguration::validateColorSpaces(bool shareOuputColorSpaces)
+{
+	Status status = Valid;
+
+	/*
+	 * Set all raw streams to the Raw color space, and make a note of the largest
+	 * non-raw stream with a defined color space (if there is one).
+	 */
+	int index = -1;
+	for (auto [i, cfg] : utils::enumerate(config_)) {
+		if (isRaw(cfg.pixelFormat))
+			cfg.colorSpace = ColorSpace::Raw;
+		else if (cfg.colorSpace && (index == -1 || cfg.size > config_[i].size))
+			index = i;
+	}
+
+	/* Make all output color spaces the same, if requested. */
+	if (index >= 0 && shareOuputColorSpaces) {
+		for (auto &cfg : config_) {
+			if (!isRaw(cfg.pixelFormat) &&
+			    cfg.colorSpace != config_[index].colorSpace) {
+				cfg.colorSpace = config_[index].colorSpace;
+				status = Adjusted;
+			}
+		}
+	}
+
+	return status;
+}
+
 /**
  * \var CameraConfiguration::transform
  * \brief User-specified transform to be applied to the image
