diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h
index 8a2e9ed5894d..d28cd921a0f9 100644
--- a/include/libcamera/internal/camera.h
+++ b/include/libcamera/internal/camera.h
@@ -36,6 +36,10 @@ public:
 	PipelineHandler *pipe() { return pipe_.get(); }
 	const PipelineHandler *pipe() const { return pipe_.get(); }
 
+	void emitBufferCompleted(Request *request, FrameBuffer *buffer);
+	void emitRequestCompleted(Request *request);
+	void emitDisconnected();
+
 	std::list<Request *> queuedRequests_;
 	std::queue<Request *> waitingRequests_;
 	ControlInfoMap controlInfo_;
diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
index 2e1e146a25b1..99aed4f0703a 100644
--- a/src/libcamera/camera.cpp
+++ b/src/libcamera/camera.cpp
@@ -611,6 +611,30 @@ Camera::Private::~Private()
  * \copydoc Camera::Private::pipe()
  */
 
+/**
+ * \fn Camera::Private::emitBufferCompleted
+ * \copydoc Camera::bufferCompleted
+ *
+ * This is one level of indirection so that we can call into the LayerManager
+ * before actually emitting the Signal.
+ */
+
+/**
+ * \fn Camera::Private::emitRequestCompleted
+ * \copydoc Camera::requestCompleted
+ *
+ * This is one level of indirection so that we can call into the LayerManager
+ * before actually emitting the Signal.
+ */
+
+/**
+ * \fn Camera::Private::emitDisconnected
+ * \copydoc Camera::disconnected
+ *
+ * This is one level of indirection so that we can call into the LayerManager
+ * before actually emitting the Signal.
+ */
+
 /**
  * \fn Camera::Private::validator()
  * \brief Retrieve the control validator related to this camera
@@ -746,6 +770,25 @@ void Camera::Private::setState(State state)
 {
 	state_.store(state, std::memory_order_release);
 }
+
+void Camera::Private::emitBufferCompleted(Request *request, FrameBuffer *buffer)
+{
+	Camera *camera = _o<Camera>();
+	camera->bufferCompleted.emit(request, buffer);
+}
+
+void Camera::Private::emitRequestCompleted(Request *request)
+{
+	Camera *camera = _o<Camera>();
+	camera->requestCompleted.emit(request);
+}
+
+void Camera::Private::emitDisconnected()
+{
+	Camera *camera = _o<Camera>();
+	camera->disconnected.emit();
+}
+
 #endif /* __DOXYGEN_PUBLIC__ */
 
 /**
@@ -956,7 +999,7 @@ void Camera::disconnect()
 	LOG(Camera, Debug) << "Disconnecting camera " << id();
 
 	_d()->disconnect();
-	disconnected.emit();
+	_d()->emitDisconnected();
 }
 
 int Camera::exportFrameBuffers(Stream *stream,
@@ -1480,7 +1523,7 @@ void Camera::requestComplete(Request *request)
 				  true))
 		LOG(Camera, Fatal) << "Trying to complete a request when stopped";
 
-	requestCompleted.emit(request);
+	_d()->emitRequestCompleted(request);
 }
 
 } /* namespace libcamera */
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index e5f9e55c9783..a7d98fe2fa65 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -552,7 +552,7 @@ void PipelineHandler::doQueueRequests(Camera *camera)
 bool PipelineHandler::completeBuffer(Request *request, FrameBuffer *buffer)
 {
 	Camera *camera = request->_d()->camera();
-	camera->bufferCompleted.emit(request, buffer);
+	camera->_d()->emitBufferCompleted(request, buffer);
 	return request->_d()->completeBuffer(buffer);
 }
 
diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp
index 7f1e11e8f913..b4ae0f41a34c 100644
--- a/src/libcamera/request.cpp
+++ b/src/libcamera/request.cpp
@@ -137,7 +137,7 @@ void Request::Private::doCancelRequest()
 
 	for (FrameBuffer *buffer : pending_) {
 		buffer->_d()->cancel();
-		camera_->bufferCompleted.emit(request, buffer);
+		camera_->_d()->emitBufferCompleted(request, buffer);
 	}
 
 	cancelled_ = true;
