diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp
index 7e9047cc8dc1..49201157eb07 100644
--- a/src/libcamera/pipeline/ipu3/imgu.cpp
+++ b/src/libcamera/pipeline/ipu3/imgu.cpp
@@ -95,12 +95,11 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index)
 
 /**
  * \brief Configure the ImgU unit input
- * \param[in] size The ImgU input frame size
+ * \param[in] pipe The ImgU pipe configuration
  * \param[in] inputFormat The format to be applied to ImgU input
  * \return 0 on success or a negative error code otherwise
  */
-int ImgUDevice::configureInput(const Size &size,
-			       V4L2DeviceFormat *inputFormat)
+int ImgUDevice::configureInput(struct Pipe *pipe, V4L2DeviceFormat *inputFormat)
 {
 	/* Configure the ImgU input video device with the requested sizes. */
 	int ret = input_->setFormat(inputFormat);
@@ -122,8 +121,8 @@ int ImgUDevice::configureInput(const Size &size,
 	Rectangle rect = {
 		.x = 0,
 		.y = 0,
-		.width = inputFormat->size.width,
-		.height = inputFormat->size.height,
+		.width = pipe->input.width,
+		.height = pipe->input.height,
 	};
 	ret = imgu_->setSelection(PAD_INPUT, V4L2_SEL_TGT_CROP, &rect);
 	if (ret)
@@ -138,7 +137,7 @@ int ImgUDevice::configureInput(const Size &size,
 
 	V4L2SubdeviceFormat imguFormat = {};
 	imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED;
-	imguFormat.size = size;
+	imguFormat.size = pipe->input;
 
 	ret = imgu_->setFormat(PAD_INPUT, &imguFormat);
 	if (ret)
diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h
index 8fb271fb8350..c0353955ea43 100644
--- a/src/libcamera/pipeline/ipu3/imgu.h
+++ b/src/libcamera/pipeline/ipu3/imgu.h
@@ -31,7 +31,7 @@ public:
 
 	int init(MediaDevice *media, unsigned int index);
 
-	int configureInput(const Size &size, V4L2DeviceFormat *inputFormat);
+	int configureInput(struct Pipe *pipe, V4L2DeviceFormat *inputFormat);
 
 	int configureOutput(const StreamConfiguration &cfg,
 			    V4L2DeviceFormat *outputFormat)
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 16bda97a3cc3..9499c127ef79 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -396,32 +396,26 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
 		outCount++;
 	}
 
-	/*
-	 * Configure the CIO2 unit with the format computed during validation
-	 * and apply the same format to the ImgU input.
-	 */
+	/* Configure the CIO2 unit with the format computed during validation. */
 	const Size &sensorSize = config->cio2Format().size;
 	V4L2DeviceFormat cio2Format = {};
 	ret = data->cio2_.configure(sensorSize, &cio2Format);
 	if (ret)
 		return ret;
 
-	ret = imgu->configureInput(sensorSize, &cio2Format);
-	if (ret)
-		return ret;
+	/*
+	 * Collect the input, output and viewfinder sizes to configure the
+	 * ImgU pipe and assign streams to configurations while iterating them.
+	 */
+	ImgUDevice::Pipe imguPipe{};
+	imguPipe.input.width = cio2Format.size.width;
+	imguPipe.input.height = cio2Format.size.height;
 
-	/* Apply the format to the configured streams output devices. */
-	bool outActive = false;
-	bool vfActive = false;
 	for (unsigned int i = 0; i < config->size(); ++i) {
 		StreamConfiguration &cfg = (*config)[i];
 		const PixelFormatInfo &info =
 			PixelFormatInfo::info(cfg.pixelFormat);
 		if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) {
-			/*
-			 * The RAW stream is configured as part of the CIO2 and
-			 * no configuration is needed for the ImgU.
-			 */
 			cfg.setStream(&data->rawStream_);
 			cfg.stride = cio2Format.planes[0].bpl;
 
@@ -437,13 +431,9 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
 		 * requested.
 		 */
 		if (cfg.size == maxOut && outCount > 1) {
-			ret = imgu->configureOutput(cfg, &outputFormat);
-			if (ret)
-				return ret;
-
-			cfg.stride = outputFormat.planes[0].bpl;
 			cfg.setStream(&data->outStream_);
-			outActive = true;
+			imguPipe.output.width = cfg.size.width;
+			imguPipe.output.height = cfg.size.height;
 
 			LOG(IPU3, Debug) << "Assigned " << cfg.toString()
 					 << " to the main output";
@@ -457,18 +447,56 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
 		 * the smaller one to reduce the cropping required (if any) on
 		 * the main output.
 		 */
-		ret = imgu->configureViewfinder(cfg, &outputFormat);
-		if (ret)
-			return ret;
-
-		cfg.stride = outputFormat.planes[0].bpl;
 		cfg.setStream(&data->vfStream_);
-		vfActive = true;
+		imguPipe.viewfinder.width = cfg.size.width;
+		imguPipe.viewfinder.height = cfg.size.height;
 
 		LOG(IPU3, Debug) << "Assigned " << cfg.toString()
 				 << " to the viewfinder output";
 	}
 
+	/*
+	 * Configure the ImgU with the collected pipe configuration and the
+	 * CIO2 unit format.
+	 */
+	ret = imgu->configureInput(&imguPipe, &cio2Format);
+	if (ret)
+		return ret;
+
+	/* Apply the format to the ImgU output devices. */
+	bool outActive = false;
+	bool vfActive = false;
+	for (unsigned int i = 0; i < config->size(); ++i) {
+		StreamConfiguration &cfg = (*config)[i];
+		Stream *stream = cfg.stream();
+
+		if (stream == &data->rawStream_) {
+			/*
+			 * The RAW stream is configured as part of the CIO2 and
+			 * no configuration is needed for the ImgU.
+			 */
+			continue;
+		}
+
+		if (stream == &data->outStream_) {
+			ret = imgu->configureOutput(cfg, &outputFormat);
+			if (ret)
+				return ret;
+
+			outActive = true;
+			cfg.stride = outputFormat.planes[0].bpl;
+		}
+
+		if (stream == &data->vfStream_) {
+			ret = imgu->configureViewfinder(cfg, &outputFormat);
+			if (ret)
+				return ret;
+
+			vfActive = true;
+			cfg.stride = outputFormat.planes[0].bpl;
+		}
+	}
+
 	/*
 	 * As we need to set format also on the non-active streams, use
 	 * the configuration of the active one for that purpose (there should
