diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index 9aa7e9eef5e7..3f9e15514ed9 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -311,14 +311,11 @@ private:
 		return static_cast<RPiCameraData *>(camera->_d());
 	}
 
-	bool registerCameras();
+	int registerCameras(MediaDevice *unicam, MediaDevice *isp, const std::string &deviceId);
 	int queueAllBuffers(Camera *camera);
 	int prepareBuffers(Camera *camera);
 	void freeBuffers(Camera *camera);
 	void mapBuffers(Camera *camera, const RPi::BufferMap &buffers, unsigned int mask);
-
-	MediaDevice *unicam_;
-	MediaDevice *isp_;
 };
 
 RPiCameraConfiguration::RPiCameraConfiguration(const RPiCameraData *data)
@@ -509,7 +506,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
 }
 
 PipelineHandlerRPi::PipelineHandlerRPi(CameraManager *manager)
-	: PipelineHandler(manager), unicam_(nullptr), isp_(nullptr)
+	: PipelineHandler(manager)
 {
 }
 
@@ -993,49 +990,85 @@ int PipelineHandlerRPi::queueRequestDevice(Camera *camera, Request *request)
 
 bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator)
 {
-	DeviceMatch unicam("unicam");
-	DeviceMatch isp("bcm2835-isp");
+	MediaDevice *unicamDevice, *ispDevice;
+	std::string deviceId;
 
-	unicam.add("unicam-image");
+	/*
+	 * String of indexes to append to the entity names when searching for
+	 * the Unican media devices. The first string is empty (un-indexed) to
+	 * to maintain backward compatability with old versions of the Unicam
+	 * kernel driver that did not advertise instance indexes.
+	 */
+	for (const std::string &id : { "", "0", "1" }) {
+		DeviceMatch unicam("unicam");
+		unicam.add("unicam" + id + "-image");
+		unicamDevice = acquireMediaDevice(enumerator, unicam);
 
-	isp.add("bcm2835-isp0-output0"); /* Input */
-	isp.add("bcm2835-isp0-capture1"); /* Output 0 */
-	isp.add("bcm2835-isp0-capture2"); /* Output 1 */
-	isp.add("bcm2835-isp0-capture3"); /* Stats */
+		if (unicamDevice) {
+			deviceId = id == "1" ? "1" : "0";
+			break;
+		}
+	}
 
-	unicam_ = acquireMediaDevice(enumerator, unicam);
-	if (!unicam_)
+	if (!unicamDevice) {
+		LOG(RPI, Debug) << "Unable to acquire a Unicam instance";
 		return false;
+	}
 
-	isp_ = acquireMediaDevice(enumerator, isp);
-	if (!isp_)
+	DeviceMatch isp("bcm2835-isp");
+	isp.add("bcm2835-isp" + deviceId + "-output0"); /* Input */
+	isp.add("bcm2835-isp" + deviceId + "-capture1"); /* Output 0 */
+	isp.add("bcm2835-isp" + deviceId + "-capture2"); /* Output 1 */
+	isp.add("bcm2835-isp" + deviceId + "-capture3"); /* Stats */
+	ispDevice = acquireMediaDevice(enumerator, isp);
+
+	if (!ispDevice) {
+		LOG(RPI, Error) << "Unable to acquire ISP instance " << deviceId;
 		return false;
+	}
+
+	int ret = registerCameras(unicamDevice, ispDevice, deviceId);
+	if (ret) {
+		LOG(RPI, Error) << "Failed to register camera: " << ret;
+		return false;
+	}
 
-	return registerCameras();
+	return true;
 }
 
-bool PipelineHandlerRPi::registerCameras()
+int PipelineHandlerRPi::registerCameras(MediaDevice *unicam, MediaDevice *isp,
+					const std::string &deviceId)
 {
 	std::unique_ptr<RPiCameraData> data = std::make_unique<RPiCameraData>(this);
+
 	if (!data->dmaHeap_.isValid())
-		return false;
+		return -ENOMEM;
+
+	MediaEntity *unicamImage = unicam->getEntityByName("unicam" + deviceId + "-image");
+	MediaEntity *ispOutput0 = isp->getEntityByName("bcm2835-isp" + deviceId + "-output0");
+	MediaEntity *ispCapture1 = isp->getEntityByName("bcm2835-isp" + deviceId + "-capture1");
+	MediaEntity *ispCapture2 = isp->getEntityByName("bcm2835-isp" + deviceId + "-capture2");
+	MediaEntity *ispCapture3 = isp->getEntityByName("bcm2835-isp" + deviceId + "-capture3");
+
+	if (!unicamImage || !ispOutput0 || !ispCapture1 || !ispCapture2 || !ispCapture3)
+		return -ENOENT;
 
 	/* Locate and open the unicam video streams. */
-	data->unicam_[Unicam::Image] = RPi::Stream("Unicam Image", unicam_->getEntityByName("unicam-image"));
+	data->unicam_[Unicam::Image] = RPi::Stream("Unicam Image", unicamImage);
 
 	/* An embedded data node will not be present if the sensor does not support it. */
-	MediaEntity *embeddedEntity = unicam_->getEntityByName("unicam-embedded");
-	if (embeddedEntity) {
-		data->unicam_[Unicam::Embedded] = RPi::Stream("Unicam Embedded", embeddedEntity);
+	MediaEntity *unicamEmbedded = unicam->getEntityByName("unicam" + deviceId + "-embedded");
+	if (unicamEmbedded) {
+		data->unicam_[Unicam::Embedded] = RPi::Stream("Unicam Embedded", unicamEmbedded);
 		data->unicam_[Unicam::Embedded].dev()->bufferReady.connect(data.get(),
 									   &RPiCameraData::unicamBufferDequeue);
 	}
 
 	/* Tag the ISP input stream as an import stream. */
-	data->isp_[Isp::Input] = RPi::Stream("ISP Input", isp_->getEntityByName("bcm2835-isp0-output0"), true);
-	data->isp_[Isp::Output0] = RPi::Stream("ISP Output0", isp_->getEntityByName("bcm2835-isp0-capture1"));
-	data->isp_[Isp::Output1] = RPi::Stream("ISP Output1", isp_->getEntityByName("bcm2835-isp0-capture2"));
-	data->isp_[Isp::Stats] = RPi::Stream("ISP Stats", isp_->getEntityByName("bcm2835-isp0-capture3"));
+	data->isp_[Isp::Input] = RPi::Stream("ISP Input", ispOutput0, true);
+	data->isp_[Isp::Output0] = RPi::Stream("ISP Output0", ispCapture1);
+	data->isp_[Isp::Output1] = RPi::Stream("ISP Output1", ispCapture2);
+	data->isp_[Isp::Stats] = RPi::Stream("ISP Stats", ispCapture3);
 
 	/* Wire up all the buffer connections. */
 	data->unicam_[Unicam::Image].dev()->frameStart.connect(data.get(), &RPiCameraData::frameStarted);
@@ -1046,7 +1079,7 @@ bool PipelineHandlerRPi::registerCameras()
 	data->isp_[Isp::Stats].dev()->bufferReady.connect(data.get(), &RPiCameraData::ispOutputDequeue);
 
 	/* Identify the sensor. */
-	for (MediaEntity *entity : unicam_->entities()) {
+	for (MediaEntity *entity : unicam->entities()) {
 		if (entity->function() == MEDIA_ENT_F_CAM_SENSOR) {
 			data->sensor_ = std::make_unique<CameraSensor>(entity);
 			break;
@@ -1054,23 +1087,23 @@ bool PipelineHandlerRPi::registerCameras()
 	}
 
 	if (!data->sensor_)
-		return false;
+		return -EINVAL;
 
 	if (data->sensor_->init())
-		return false;
+		return -EINVAL;
 
 	data->sensorFormats_ = populateSensorFormats(data->sensor_);
 
 	ipa::RPi::SensorConfig sensorConfig;
 	if (data->loadIPA(&sensorConfig)) {
 		LOG(RPI, Error) << "Failed to load a suitable IPA library";
-		return false;
+		return -EINVAL;
 	}
 
-	if (sensorConfig.sensorMetadata ^ !!embeddedEntity) {
+	if (sensorConfig.sensorMetadata ^ !!unicamEmbedded) {
 		LOG(RPI, Warning) << "Mismatch between Unicam and CamHelper for embedded data usage!";
 		sensorConfig.sensorMetadata = false;
-		if (embeddedEntity)
+		if (unicamEmbedded)
 			data->unicam_[Unicam::Embedded].dev()->bufferReady.disconnect();
 	}
 
@@ -1091,12 +1124,12 @@ bool PipelineHandlerRPi::registerCameras()
 
 	for (auto stream : data->streams_) {
 		if (stream->dev()->open())
-			return false;
+			continue;
 	}
 
 	if (!data->unicam_[Unicam::Image].dev()->caps().hasMediaController()) {
 		LOG(RPI, Error) << "Unicam driver does not use the MediaController, please update your kernel!";
-		return false;
+		return -EINVAL;
 	}
 
 	/*
@@ -1158,7 +1191,7 @@ bool PipelineHandlerRPi::registerCameras()
 
 	if (!bayerFormat.isValid()) {
 		LOG(RPI, Error) << "No Bayer format found";
-		return false;
+		return -EINVAL;
 	}
 	data->nativeBayerOrder_ = bayerFormat.order;
 
@@ -1173,12 +1206,14 @@ bool PipelineHandlerRPi::registerCameras()
 	streams.insert(&data->isp_[Isp::Output1]);
 
 	/* Create and register the camera. */
-	const std::string &id = data->sensor_->id();
+	const std::string &cameraId = data->sensor_->id();
 	std::shared_ptr<Camera> camera =
-		Camera::create(std::move(data), id, streams);
+		Camera::create(std::move(data), cameraId, streams);
 	registerCamera(std::move(camera));
 
-	return true;
+	LOG(RPI, Info) << "Registered camera " << cameraId
+		       << " to instance \"" << deviceId << "\"";
+	return 0;
 }
 
 int PipelineHandlerRPi::queueAllBuffers(Camera *camera)
