diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 44e5eb48549e..4ed8c1fec1e3 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -140,6 +140,7 @@ private:
 		ImgUDevice *imgu;
 
 		Stream streams_[IPU3_STREAMS_COUNT];
+		unsigned int activeStreamsMask;
 	};
 
 	IPU3CameraData *cameraData(const Camera *camera)
@@ -148,6 +149,44 @@ private:
 			PipelineHandler::cameraData(camera));
 	}
 
+	bool isOutput(IPU3CameraData *data, Stream *stream)
+	{
+		return &data->streams_[IPU3_STREAM_OUTPUT] == stream;
+	}
+	bool isOutputActive(IPU3CameraData *data)
+	{
+		return (data->activeStreamsMask & (1 << IPU3_STREAM_OUTPUT)) ?
+			true : false;
+	}
+	void setOutputActive(IPU3CameraData *data)
+	{
+		data->activeStreamsMask |= (1 << IPU3_STREAM_OUTPUT);
+	}
+	bool isViewfinder(IPU3CameraData *data, Stream *stream)
+	{
+		return &data->streams_[IPU3_STREAM_VF] == stream;
+	}
+	bool isViewfinderActive(IPU3CameraData *data)
+	{
+		return (data->activeStreamsMask & (1 << IPU3_STREAM_VF)) ?
+			true : false;
+	}
+	void setViewfinderActive(IPU3CameraData *data)
+	{
+		data->activeStreamsMask |= (1 << IPU3_STREAM_VF);
+	}
+	bool isStreamActive(IPU3CameraData *data, Stream *stream)
+	{
+		if (isOutput(data, stream) &&
+		    isOutputActive(data))
+			return true;
+		if (isViewfinder(data, stream) &&
+		    isViewfinderActive(data))
+			return true;
+
+		return false;
+	}
+
 	int mediaBusToCIO2Format(unsigned int code);
 	V4L2Device *openDevice(MediaDevice *media, const std::string &name);
 	V4L2Subdevice *openSubdevice(MediaDevice *media,
@@ -158,9 +197,17 @@ private:
 
 	int initImgU(ImgUDevice *imgu);
 
-	int setImguFormat(ImgUDevice *imguDevice,
-			  const StreamConfiguration &config,
-			  Rectangle *rect);
+	int setInputFormat(ImgUDevice *imguDevice,
+			   const StreamConfiguration &config,
+			   Rectangle *rect);
+	int setOutputFormat(ImgUDevice *imguDevice,
+			    V4L2Device *output,
+			    const StreamConfiguration &config);
+	int setViewfinderFormat(ImgUDevice *imguDevice,
+				V4L2Device *Viewfinder,
+				const StreamConfiguration &config);
+	int setStatFormat(ImgUDevice *imguDevice,
+			  const StreamConfiguration &config);
 	int setCIO2Format(CIO2Device *cio2Device,
 			  const StreamConfiguration &config,
 			  V4L2SubdeviceFormat *format);
@@ -251,32 +298,66 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera,
 }
 
 int PipelineHandlerIPU3::configureStreams(Camera *camera,
-					  std::map<Stream *, StreamConfiguration> &config)
+					  std::map<Stream *,
+						   StreamConfiguration> &config)
 {
 	IPU3CameraData *data = cameraData(camera);
-	const StreamConfiguration &cfg = config[&data->streams_[0]];
 	V4L2Device *viewfinder = data->imgu->viewfinder;
 	V4L2Device *output = data->imgu->output;
 	V4L2Device *input = data->imgu->input;
 	V4L2Device *cio2 = data->cio2.output;
+	StreamConfiguration CIO2Config = {};
 	int ret;
 
-	LOG(IPU3, Info)
-		<< "Requested image format: " << cfg.width << "x"
-		<< cfg.height << " - " << std::hex << std::setw(8)
-		<< cfg.pixelFormat << " on camera:'" << camera->name() << "'";
+	/* Remove previously configured stream masks to store the new ones. */
+	data->activeStreamsMask = 0;
 
-	/*
-	 * Verify that the requested size respects the IPU3 alignement
-	 * requirements: the image width shall be a multiple of 8 pixels and
-	 * its height a multiple of 4 pixels.
-	 *
-	 * \todo: consider the BDS scaling factor requirements:
-	 * "the downscaling factor must be an integer value multiple of 1/32"
-	 */
-	if (cfg.width % 8 || cfg.height % 4) {
-		LOG(IPU3, Error) << "Stream format not support: bad alignement";
-		return -EINVAL;
+	for (auto const &streamConfig : config) {
+		Stream *stream = streamConfig.first;
+		const StreamConfiguration &cfg = streamConfig.second;
+
+		/*
+		 * Verify that the requested size respects the IPU3 alignement
+		 * requirements: the image width shall be a multiple of 8 pixels
+		 * and its height a multiple of 4 pixels.
+		 *
+		 * \todo: consider the BDS scaling factor requirements: "the
+		 * downscaling factor must be an integer value multiple of 1/32"
+		 */
+		if (cfg.width % 8 || cfg.height % 4) {
+			LOG(IPU3, Error)
+				<< "Stream format not support: bad alignement";
+			return -EINVAL;
+		}
+
+		LOG(IPU3, Info)
+			<< "Requested image format: " << cfg.width << "x"
+			<< cfg.height << " - " << std::hex << std::setw(8)
+			<< cfg.pixelFormat << " on camera:'" << camera->name()
+			<< "'";
+
+		/*
+		 * FIXME: As viewfinder should be operated even when
+		 * applications do not intend to use it, we need to keep track
+		 * of which streams have to be configured, to make meaningful
+		 * decisions at configure and request queueing time.
+		 *
+		 * Walk here all the streams to configure and collect the
+		 * active ones in a bitmaks.
+		 */
+		if (isOutput(data, stream))
+			setOutputActive(data);
+		if (isViewfinder(data, stream))
+			setViewfinderActive(data);
+
+		/*
+		 * Collect the maximum width and height: IPU3 can downscale
+		 * only.
+		 */
+		if (cfg.width > CIO2Config.width)
+			CIO2Config.width = cfg.width;
+		if (cfg.height > CIO2Config.height)
+			CIO2Config.height = cfg.height;
 	}
 
 	/*
@@ -293,7 +374,7 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera,
 	 * input.
 	 */
 	V4L2SubdeviceFormat sensorFormat = {};
-	ret = setCIO2Format(&data->cio2, cfg, &sensorFormat);
+	ret = setCIO2Format(&data->cio2, CIO2Config, &sensorFormat);
 	if (ret)
 		return ret;
 
@@ -307,41 +388,64 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera,
 	if (ret)
 		return ret;
 
-	LOG(IPU3, Debug)
-		<< "CIO2 output format = " << cio2Format.toString();
+	LOG(IPU3, Debug) << "CIO2 output format = " << cio2Format.toString();
 
 	ret = input->setFormat(&cio2Format);
 	if (ret)
 		return ret;
 
-	/* Apply pad formats and crop/compose rectangle to the ImgU. */
+	/* Apply pad formats and crop/compose rectangle to the ImgU input. */
 	Rectangle rect = {
 		.x = 0,
 		.y = 0,
 		.w = cio2Format.width,
 		.h = cio2Format.height,
 	};
-	ret = setImguFormat(data->imgu, cfg, &rect);
+	ret = setInputFormat(data->imgu, CIO2Config, &rect);
 	if (ret)
 		return ret;
 
-	/* Apply the format to the ImgU output and viewfinder devices. */
-	V4L2DeviceFormat outputFormat = {};
-	outputFormat.width = cfg.width;
-	outputFormat.height = cfg.height;
-	outputFormat.fourcc = V4L2_PIX_FMT_NV12;
-	outputFormat.planesCount = 2;
+	for (auto const &streamConfig : config) {
+		Stream *stream = streamConfig.first;
+		const StreamConfiguration &cfg = streamConfig.second;
 
-	ret = output->setFormat(&outputFormat);
-	if (ret)
-		return ret;
+		if (isOutput(data, stream)) {
+			ret = setOutputFormat(data->imgu, output, cfg);
+			if (ret)
+				return ret;
 
-	LOG(IPU3, Debug)
-		<< "ImgU output format = " << outputFormat.toString();
+			ret = setStatFormat(data->imgu, cfg);
+			if (ret)
+				return ret;
 
-	ret = viewfinder->setFormat(&outputFormat);
-	if (ret)
-		return ret;
+			/*
+			 * FIXME: even if viewfinder is not in use, we need to
+			 * configure and operate it. Use the same size used
+			 * for main output.
+			 */
+			if (!isViewfinderActive(data)) {
+				ret = setViewfinderFormat(data->imgu,
+							  viewfinder, cfg);
+				if (ret)
+					return ret;
+			}
+		} else if (isViewfinder(data, stream)) {
+			ret = setViewfinderFormat(data->imgu, viewfinder, cfg);
+			if (ret)
+				return ret;
+
+			/* Operating the main output is mandatory. */
+			if (!isOutputActive(data)) {
+				ret = setOutputFormat(data->imgu, output, cfg);
+				if (ret)
+					return ret;
+
+				ret = setStatFormat(data->imgu, cfg);
+				if (ret)
+					return ret;
+			}
+		}
+	}
 
 	return 0;
 }
@@ -974,9 +1078,9 @@ void PipelineHandlerIPU3::deleteCIO2(CIO2Device *cio2)
 	delete cio2->sensor;
 }
 
-int PipelineHandlerIPU3::setImguFormat(ImgUDevice *imguDevice,
-				       const StreamConfiguration &config,
-				       Rectangle *rect)
+int PipelineHandlerIPU3::setInputFormat(ImgUDevice *imguDevice,
+					const StreamConfiguration &config,
+					Rectangle *rect)
 {
 	V4L2Subdevice *imgu = imguDevice->imgu;
 	int ret;
@@ -1012,17 +1116,86 @@ int PipelineHandlerIPU3::setImguFormat(ImgUDevice *imguDevice,
 	if (ret)
 		return ret;
 
+	LOG(IPU3, Debug) << "ImgU GDC format = " << imguFormat.toString();
+
+	return 0;
+}
+
+int PipelineHandlerIPU3::setOutputFormat(ImgUDevice *imguDevice,
+					 V4L2Device *output,
+					 const StreamConfiguration &config)
+{
+	V4L2Subdevice *imgu = imguDevice->imgu;
+	int ret;
+
+	V4L2SubdeviceFormat imguFormat = {};
+	imguFormat.width = config.width;
+	imguFormat.height = config.height;
+	imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED;
+
 	ret = imgu->setFormat(ImgUDevice::PAD_OUTPUT, &imguFormat);
 	if (ret)
 		return ret;
 
+	V4L2DeviceFormat outputFormat = {};
+	outputFormat.width = config.width;
+	outputFormat.height = config.height;
+	outputFormat.fourcc = V4L2_PIX_FMT_NV12;
+	outputFormat.planesCount = 2;
+
+	ret = output->setFormat(&outputFormat);
+	if (ret)
+		return ret;
+
 	LOG(IPU3, Debug)
-		<< "ImgU GDC format = " << imguFormat.toString();
+		<< "ImgU output format = " << outputFormat.toString();
+
+	return 0;
+}
+
+int PipelineHandlerIPU3::setViewfinderFormat(ImgUDevice *imguDevice,
+					     V4L2Device *viewfinder,
+					     const StreamConfiguration &config)
+{
+	V4L2Subdevice *imgu = imguDevice->imgu;
+	int ret;
+
+	V4L2SubdeviceFormat imguFormat = {};
+	imguFormat.width = config.width;
+	imguFormat.height = config.height;
+	imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED;
 
 	ret = imgu->setFormat(ImgUDevice::PAD_VF, &imguFormat);
 	if (ret)
 		return ret;
 
+	V4L2DeviceFormat viewfinderFormat = {};
+	viewfinderFormat.width = config.width;
+	viewfinderFormat.height = config.height;
+	viewfinderFormat.fourcc = V4L2_PIX_FMT_NV12;
+	viewfinderFormat.planesCount = 2;
+
+	ret = viewfinder->setFormat(&viewfinderFormat);
+	if (ret)
+		return ret;
+
+	LOG(IPU3, Debug)
+		<< "ImgU viewfinder format = " << viewfinderFormat.toString();
+
+	return 0;
+}
+
+int PipelineHandlerIPU3::setStatFormat(ImgUDevice *imguDevice,
+				       const StreamConfiguration &config)
+{
+	V4L2Subdevice *imgu = imguDevice->imgu;
+	int ret;
+
+	V4L2SubdeviceFormat imguFormat = {};
+	imguFormat.width = config.width;
+	imguFormat.height = config.height;
+	imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED;
+
 	ret = imgu->setFormat(ImgUDevice::PAD_STAT, &imguFormat);
 	if (ret)
 		return ret;
