diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 363b24ceead2..ad866346e13c 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -62,6 +62,9 @@ public:
 	V4L2Device *viewfinder;
 	V4L2Device *stat;
 	/* \todo Add param video device for 3A tuning */
+
+	BufferPool vfPool;
+	BufferPool statPool;
 };
 
 struct CIO2Device {
@@ -80,6 +83,8 @@ struct CIO2Device {
 	V4L2Device *output;
 	V4L2Subdevice *csi2;
 	V4L2Subdevice *sensor;
+
+	BufferPool pool;
 };
 
 class IPU3CameraData : public CameraData
@@ -123,6 +128,8 @@ public:
 private:
 	static constexpr unsigned int IPU3_IMGU_COUNT = 2;
 	static constexpr unsigned int IPU3_BUFFER_COUNT = 4;
+	static constexpr unsigned int IPU3_CIO2_BUFFER_COUNT = 4;
+	static constexpr unsigned int IPU3_IMGU_BUFFER_COUNT = 4;
 
 	IPU3CameraData *cameraData(const Camera *camera)
 	{
@@ -305,16 +312,47 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera,
 
 int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream)
 {
-	const StreamConfiguration &cfg = stream->configuration();
 	IPU3CameraData *data = cameraData(camera);
+	V4L2Device *viewfinder = data->imgu->viewfinder;
+	V4L2Device *output = data->imgu->output;
+	V4L2Device *input = data->imgu->input;
 	V4L2Device *cio2 = data->cio2.output;
+	V4L2Device *stat = data->imgu->stat;
+	int ret;
 
-	if (!cfg.bufferCount)
-		return -EINVAL;
+	/* Share buffers between CIO2 output and ImgU input. */
+	data->cio2.pool.createBuffers(IPU3_CIO2_BUFFER_COUNT);
+	ret = cio2->exportBuffers(&data->cio2.pool);
+	if (ret) {
+		LOG(IPU3, Error) << "Failed to reserve CIO2 memory";
+		return ret;
+	}
+
+	ret = input->importBuffers(&data->cio2.pool);
+	if (ret) {
+		LOG(IPU3, Error) << "Failed to import ImgU memory";
+		return ret;
+	}
+
+	/* Prepare the buffer pools for viewfinder and stat. */
+	data->imgu->vfPool.createBuffers(IPU3_IMGU_BUFFER_COUNT);
+	ret = viewfinder->exportBuffers(&data->imgu->vfPool);
+	if (ret) {
+		LOG(IPU3, Error) << "Failed to reserve ImgU viewfinder memory";
+		return ret;
+	}
+
+	data->imgu->statPool.createBuffers(IPU3_IMGU_BUFFER_COUNT);
+	ret = stat->exportBuffers(&data->imgu->statPool);
+	if (ret) {
+		LOG(IPU3, Error) << "Failed to reserve ImgU stat memory";
+		return ret;
+	}
 
-	int ret = cio2->exportBuffers(&stream->bufferPool());
+	/* Export ImgU output buffers to the stream's pool. */
+	ret = output->exportBuffers(&stream->bufferPool());
 	if (ret) {
-		LOG(IPU3, Error) << "Failed to request memory";
+		LOG(IPU3, Error) << "Failed to reserve ImgU output memory";
 		return ret;
 	}
 
