diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h
index 1fdef9ce..f16f37ab 100644
--- a/src/libcamera/include/pipeline_handler.h
+++ b/src/libcamera/include/pipeline_handler.h
@@ -30,6 +30,48 @@ class MediaDevice;
 class PipelineHandler;
 class Request;
 
+class DeviceID
+{
+public:
+	DeviceID(std::string type)
+		: type_(type){};
+	~DeviceID(){};
+
+	template<class IDType>
+	bool compare(const DeviceID &id) const
+	{
+		return this->type_.compare(id.type_) ||
+		       static_cast<const IDType *>(this)->compare(static_cast<const IDType &>(id));
+	}
+
+	const std::string type_;
+};
+
+class PCIDeviceID : public DeviceID
+{
+public:
+	PCIDeviceID(uint16_t vendor, uint16_t device)
+		: DeviceID("pci"), vendor_(vendor), device_(device){};
+	~PCIDeviceID(){};
+
+	bool compare(const PCIDeviceID &pci) const
+	{
+		uint32_t thisID = (vendor_ << 16) + device_;
+		uint32_t otherID = (pci.vendor_ << 16) + pci.device_;
+
+		return thisID < otherID;
+	}
+
+	const uint16_t vendor_;
+	const uint16_t device_;
+};
+
+template<class IDType>
+bool compareDevices(const DeviceID &id1, const DeviceID &id2)
+{
+	return id1.compare<IDType>(id2);
+}
+
 class CameraData
 {
 public:
@@ -117,6 +159,10 @@ public:
 
 	static void registerType(PipelineHandlerFactory *factory);
 	static std::vector<PipelineHandlerFactory *> &factories();
+	static std::vector<std::reference_wrapper<DeviceID>> &getDeviceIDs();
+
+protected:
+	virtual std::vector<DeviceID> &deviceIDs() = 0;
 
 private:
 	virtual PipelineHandler *createInstance(CameraManager *manager) = 0;
@@ -124,12 +170,22 @@ private:
 	std::string name_;
 };
 
-#define REGISTER_PIPELINE_HANDLER(handler)				\
+#define P99_PROTECT(...) __VA_ARGS__
+
+#define REGISTER_PIPELINE_HANDLER(handler, cameras)			\
 class handler##Factory final : public PipelineHandlerFactory		\
 {									\
 public:									\
 	handler##Factory() : PipelineHandlerFactory(#handler) {}	\
 									\
+protected:								\
+	std::vector<DeviceID> &deviceIDs()				\
+	{								\
+		static std::vector<DeviceID> handler##Cameras =		\
+		       std::vector<DeviceID>(cameras);			\
+		return handler##Cameras;				\
+	}								\
+									\
 private:								\
 	PipelineHandler *createInstance(CameraManager *manager)		\
 	{								\
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 827906d5..562ee9fb 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -1504,6 +1504,8 @@ int CIO2Device::mediaBusToFormat(unsigned int code)
 	}
 }
 
-REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3);
+REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3,
+			  P99_PROTECT({ PCIDeviceID(0x8086, 0x1919),
+					PCIDeviceID(0x8086, 0x9D32) }));
 
 } /* namespace libcamera */
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index de4ab523..85225f9b 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -513,6 +513,6 @@ void PipelineHandlerRkISP1::bufferReady(Buffer *buffer)
 	completeRequest(activeCamera_, request);
 }
 
-REGISTER_PIPELINE_HANDLER(PipelineHandlerRkISP1);
+REGISTER_PIPELINE_HANDLER(PipelineHandlerRkISP1, {});
 
 } /* namespace libcamera */
diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp
index 89652105..376eb92a 100644
--- a/src/libcamera/pipeline/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo.cpp
@@ -390,6 +390,6 @@ void UVCCameraData::bufferReady(Buffer *buffer)
 	pipe_->completeRequest(camera_, request);
 }
 
-REGISTER_PIPELINE_HANDLER(PipelineHandlerUVC);
+REGISTER_PIPELINE_HANDLER(PipelineHandlerUVC, {});
 
 } /* namespace libcamera */
diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp
index f26a91f8..75d0236f 100644
--- a/src/libcamera/pipeline/vimc.cpp
+++ b/src/libcamera/pipeline/vimc.cpp
@@ -459,6 +459,6 @@ void VimcCameraData::bufferReady(Buffer *buffer)
 	pipe_->completeRequest(camera_, request);
 }
 
-REGISTER_PIPELINE_HANDLER(PipelineHandlerVimc);
+REGISTER_PIPELINE_HANDLER(PipelineHandlerVimc, {});
 
 } /* namespace libcamera */
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 3e54aa23..9113bf18 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -593,6 +593,22 @@ std::vector<PipelineHandlerFactory *> &PipelineHandlerFactory::factories()
 	return factories;
 }
 
+std::vector<std::reference_wrapper<DeviceID>> &PipelineHandlerFactory::getDeviceIDs()
+{
+	static std::vector<std::reference_wrapper<DeviceID>> devices;
+	if (!devices.empty())
+		return devices;
+
+	std::vector<PipelineHandlerFactory *> &factories = PipelineHandlerFactory::factories();
+
+	for (PipelineHandlerFactory *factory : factories) {
+		std::vector<DeviceID> &factoryDevices = factory->deviceIDs();
+		devices.insert(devices.end(), factoryDevices.begin(), factoryDevices.end());
+	}
+
+	return devices;
+}
+
 /**
  * \fn PipelineHandlerFactory::createInstance()
  * \brief Create an instance of the PipelineHandler corresponding to the factory
