diff --git a/include/FeedingFanOut.h b/include/FeedingFanOut.h
index e66a9255d642a6ad70dce11a2d77b831d06f073d..b6ac2d04fd0adc22be7e5a65081084f0889b069c 100644
--- a/include/FeedingFanOut.h
+++ b/include/FeedingFanOut.h
@@ -23,9 +23,10 @@ namespace ChimeraTK {
     public:
 
       FeedingFanOut(std::string const &name, std::string const &unit, std::string const &description,
-                    size_t numberOfElements)
+                    size_t numberOfElements, bool withReturn)
       : FanOut<UserType>(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>>()),
-        ChimeraTK::NDRegisterAccessor<UserType>(name, unit, description)
+        ChimeraTK::NDRegisterAccessor<UserType>("FeedingFanOut:"+name, unit, description),
+        _withReturn(withReturn)
       {
         ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D.resize(1);
         ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0].resize(numberOfElements);
@@ -33,9 +34,7 @@ namespace ChimeraTK {
 
       /** Add a slave to the FanOut. Only sending end-points of a consuming node may be added. */
       void addSlave(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave) override {
-        if(!slave->isWriteable()) {
-          throw ChimeraTK::logic_error("FeedingFanOut::addSlave() has been called with a receiving implementation!");
-        }
+
         // check if array shape is compatible, unless the receiver is a trigger node, so no data is expected
         if( slave->getNumberOfSamples() != 0 &&
             ( slave->getNumberOfChannels() != 1 || slave->getNumberOfSamples() != this->getNumberOfSamples() ) ) {
@@ -43,11 +42,35 @@ namespace ChimeraTK {
           what += "' with incompatible array shape! Name of fan out: '" + this->getName() + "'";
           throw ChimeraTK::logic_error(what.c_str());
         }
+
+        // make sure slave is writeable
+        if(!slave->isWriteable()) {
+          throw ChimeraTK::logic_error("FeedingFanOut::addSlave() has been called with a receiving implementation!");
+        }
+
+        // handle return channels
+        if(_withReturn) {
+          if(slave->isReadable()) {
+            if(_hasReturnSlave) {
+              throw ChimeraTK::logic_error("FeedingFanOut: Cannot add multiple slaves with return channel!");
+            }
+            _hasReturnSlave = true;
+            _returnSlave = slave;
+          }
+        }
+        else {
+          if(slave->isReadable()) {
+            throw ChimeraTK::logic_error("FeedingFanOut: Cannot add slaves with return channel to FeedingFanOuts "
+                                         "without return channel!");
+          }
+        }
+
+        // add the slave
         FanOut<UserType>::slaves.push_back(slave);
       }
 
       bool isReadable() const override {
-        return false;
+        return _withReturn;
       }
 
       bool isReadOnly() const override {
@@ -59,27 +82,45 @@ namespace ChimeraTK {
       }
 
       void doReadTransfer() override {
-        throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        if(!_withReturn) throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        _returnSlave->doReadTransfer();
       }
 
       bool doReadTransferNonBlocking() override {
-        throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        if(!_withReturn) throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        return _returnSlave->doReadTransferNonBlocking();
       }
 
       bool doReadTransferLatest() override {
-        throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        if(!_withReturn) throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        return _returnSlave->doReadTransferLatest();
       }
 
       void doPreRead() override {
-        throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        if(!_withReturn) throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        _returnSlave->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
+        _returnSlave->preRead();
       }
 
       void doPostRead() override {
-        throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        if(!_withReturn) throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        assert(_hasReturnSlave);
+        _returnSlave->postRead();
+        _returnSlave->accessChannel(0).swap(ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
+        // distribute return-channel update to the other slaves
+        for(auto &slave : FanOut<UserType>::slaves) {     // send out copies to slaves
+          if(slave == _returnSlave) continue;
+          if(slave->getNumberOfSamples() != 0) {          // do not send copy if no data is expected (e.g. trigger)
+            slave->accessChannel(0) = ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0];
+          }
+          slave->write(_returnSlave->getVersionNumber());
+        }
+
       }
 
       ChimeraTK::TransferFuture doReadTransferAsync() override {
-        throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        if(!_withReturn) throw ChimeraTK::logic_error("Read operation called on write-only variable.");
+        return {_returnSlave->doReadTransferAsync(), this};
       }
 
       void doPreWrite() override {
@@ -133,10 +174,26 @@ namespace ChimeraTK {
         /// @todo implement properly?
       }
 
-      AccessModeFlags getAccessModeFlags() const override { return {}; }
+      AccessModeFlags getAccessModeFlags() const override { return {AccessMode::wait_for_new_data}; }
 
       VersionNumber getVersionNumber() const override { return FanOut<UserType>::slaves.front()->getVersionNumber(); }
 
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> getReturnSlave() {
+        return _returnSlave;
+      }
+
+    protected:
+
+      /// Flag whether this FeedingFanOut has a return channel. Is specified in the constructor
+      bool _withReturn;
+
+      /// Used if _withReturn is true: flag whether the corresponding slave with the return channel has already been
+      /// added.
+      bool _hasReturnSlave{false};
+
+      /// The slave with return channel
+      boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> _returnSlave;
+
   };
 
 } /* namespace ChimeraTK */
diff --git a/include/TestableModeAccessorDecorator.h b/include/TestableModeAccessorDecorator.h
index 47596f989d4839cae50404cfcf3cc59c71b83f37..fb07c0af739635e30b33647a804405faae258b16 100644
--- a/include/TestableModeAccessorDecorator.h
+++ b/include/TestableModeAccessorDecorator.h
@@ -11,6 +11,7 @@
 #include <ChimeraTK/NDRegisterAccessorDecorator.h>
 
 #include "Application.h"
+#include "FeedingFanOut.h"
 
 namespace ChimeraTK {
 
@@ -37,7 +38,9 @@ namespace ChimeraTK {
         // if this decorating a bidirectional process variable, set the valueRejectCallback
         auto bidir = boost::dynamic_pointer_cast<BidirectionalProcessArray<UserType>>(accessor);
         if(bidir) {
-          bidir->setValueRejectCallback([this]{decrementCounter();});
+          bidir->setValueRejectCallback([this]{
+            decrementCounter();
+          });
         }
 
       }
diff --git a/include/TriggerFanOut.h b/include/TriggerFanOut.h
index 7799bc6798b034adb1d798d50d4c95735c463efc..26431256baff31646f8f57d0f8ff304b7af1c986 100644
--- a/include/TriggerFanOut.h
+++ b/include/TriggerFanOut.h
@@ -54,7 +54,7 @@ namespace ChimeraTK {
         assert(feedingNode.get() != nullptr);
         transferGroup.addAccessor(feedingNode);
         auto feedingFanOut = boost::make_shared<FeedingFanOut<UserType>>( feedingNode->getName(), feedingNode->getUnit(),
-            feedingNode->getDescription(), feedingNode->getNumberOfSamples() );
+            feedingNode->getDescription(), feedingNode->getNumberOfSamples(), false );    // in TriggerFanOuts we cannot have return channels
         boost::fusion::at_key<UserType>(fanOutMap.table)[feedingNode] = feedingFanOut;
         return feedingFanOut;
       }
diff --git a/tests/executables_src/testBidirectionalVariables.cc b/tests/executables_src/testBidirectionalVariables.cc
index 73af76609c16f5891b51157271628eed19fc04e3..f11562f8f6c8e0f780b4991f741a4b39fcb459cf 100644
--- a/tests/executables_src/testBidirectionalVariables.cc
+++ b/tests/executables_src/testBidirectionalVariables.cc
@@ -101,12 +101,9 @@ BOOST_AUTO_TEST_CASE(testNormalOperation) {
 
     TestApplication app;
 
-    //app.a.connectTo(app.cs);
-    //app.b.connectTo(app.cs);
-    app.cs("var1") >> app.a.var1;
-    app.a.var2 >> app.b.var2;
-    app.cs("max") >> app.b.max;
-    app.cs("var3") >> app.b.var3;
+    // the connections will result in a FeedingFanOut for var2, as it is connected to the control system as well
+    app.a.connectTo(app.cs);
+    app.b.connectTo(app.cs);
     ctk::TestFacility test;
     app.initialise();
     app.run();