diff --git a/packages/autopeering/selection/common.go b/packages/autopeering/selection/common.go
index 679de027c35d405f3a0faf24686c5007cf3b03a1..60bff450316a9d78789e0a9d1bd027fabc4cd3b8 100644
--- a/packages/autopeering/selection/common.go
+++ b/packages/autopeering/selection/common.go
@@ -3,7 +3,7 @@ package selection
 import (
 	"time"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
+	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
 	"github.com/iotaledger/hive.go/logger"
 )
 
@@ -30,10 +30,22 @@ type Config struct {
 	Log *logger.Logger
 
 	// These settings are optional:
-	DropOnUpdate     bool          // set true to drop all neighbors when the salt is updated
-	RequiredServices []service.Key // services required in order to select/be selected during autopeering
+	DropOnUpdate      bool      // set true to drop all neighbors when the salt is updated
+	NeighborValidator Validator // potential neighbor validator
 }
 
+// A Validator checks whether a peer is a valid neighbor
+type Validator interface {
+	IsValid(*peer.Peer) bool
+}
+
+// The ValidatorFunc type is an adapter to allow the use of ordinary functions as neighbor validators.
+// If f is a function with the appropriate signature, ValidatorFunc(f) is a Validator that calls f.
+type ValidatorFunc func(p *peer.Peer) bool
+
+// IsValid calls f(p).
+func (f ValidatorFunc) IsValid(p *peer.Peer) bool { return f(p) }
+
 // Parameters holds the parameters that can be configured.
 type Parameters struct {
 	InboundNeighborSize        int           // number of inbound neighbors
diff --git a/packages/autopeering/selection/manager.go b/packages/autopeering/selection/manager.go
index ae58fd5359dbb7282568356e14edcc064dfdfa6f..313d3c7cf2014d0338237b64476cc97dd592c0cf 100644
--- a/packages/autopeering/selection/manager.go
+++ b/packages/autopeering/selection/manager.go
@@ -5,7 +5,6 @@ import (
 	"time"
 
 	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
 	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
 	"github.com/iotaledger/hive.go/logger"
 )
@@ -35,8 +34,8 @@ type manager struct {
 	net               network
 	getPeersToConnect func() []*peer.Peer
 	log               *logger.Logger
-	dropOnUpdate      bool          // set true to drop all neighbors when the salt is updated
-	requiredServices  []service.Key // services required in order to select/be selected during autopeering
+	dropOnUpdate      bool      // set true to drop all neighbors when the salt is updated
+	neighborValidator Validator // potential neighbor validator
 
 	inbound  *Neighborhood
 	outbound *Neighborhood
@@ -57,7 +56,7 @@ func newManager(net network, peersFunc func() []*peer.Peer, log *logger.Logger,
 		getPeersToConnect: peersFunc,
 		log:               log,
 		dropOnUpdate:      config.DropOnUpdate,
-		requiredServices:  config.RequiredServices,
+		neighborValidator: config.NeighborValidator,
 		inbound:           NewNeighborhood(inboundNeighborSize),
 		outbound:          NewNeighborhood(outboundNeighborSize),
 		rejectionFilter:   NewFilter(),
@@ -217,9 +216,12 @@ func (m *manager) updateOutbound(resultChan chan<- peer.PeerDistance) {
 
 	// filter out current neighbors
 	filter := m.getConnectedFilter()
-	filteredList := filter.Apply(distList)
+	if m.neighborValidator != nil {
+		filter.AddCondition(m.neighborValidator.IsValid)
+	}
+
 	// filter out previous rejections
-	filteredList = m.rejectionFilter.Apply(filteredList)
+	filteredList := m.rejectionFilter.Apply(filter.Apply(distList))
 	if len(filteredList) == 0 {
 		return
 	}
@@ -340,13 +342,10 @@ func (m *manager) isValidNeighbor(p *peer.Peer) bool {
 	if m.getID() == p.ID() {
 		return false
 	}
-	// reject if required services are missing
-	for _, reqService := range m.requiredServices {
-		if p.Services().Get(reqService) == nil {
-			return false
-		}
+	if m.neighborValidator == nil {
+		return true
 	}
-	return true
+	return m.neighborValidator.IsValid(p)
 }
 
 func (m *manager) triggerPeeringEvent(isOut bool, p *peer.Peer, status bool) {
diff --git a/packages/autopeering/selection/selection.go b/packages/autopeering/selection/selection.go
index 66183f246131b9d9cf9cdad18888166f44d346a3..f27393accdef5d234c46c4f7de5b092c5a11e21f 100644
--- a/packages/autopeering/selection/selection.go
+++ b/packages/autopeering/selection/selection.go
@@ -11,8 +11,9 @@ type Selector interface {
 }
 
 type Filter struct {
-	internal map[peer.ID]bool
-	lock     sync.RWMutex
+	internal   map[peer.ID]bool
+	conditions []func(*peer.Peer) bool
+	lock       sync.RWMutex
 }
 
 func NewFilter() *Filter {
@@ -21,29 +22,23 @@ func NewFilter() *Filter {
 	}
 }
 
-func (f *Filter) Apply(list []peer.PeerDistance) (filteredList []peer.PeerDistance) {
+func (f *Filter) Apply(list []peer.PeerDistance) (filtered []peer.PeerDistance) {
 	f.lock.RLock()
 	defer f.lock.RUnlock()
-	for _, p := range list {
-		if !f.internal[p.Remote.ID()] {
-			filteredList = append(filteredList, p)
-		}
-	}
-	return filteredList
-}
 
-func (f *Filter) PushBack(list []peer.PeerDistance) (filteredList []peer.PeerDistance) {
-	var head, tail []peer.PeerDistance
-	f.lock.RLock()
-	defer f.lock.RUnlock()
+list:
 	for _, p := range list {
-		if f.internal[p.Remote.ID()] {
-			tail = append(tail, p)
-		} else {
-			head = append(head, p)
+		if _, contains := f.internal[p.Remote.ID()]; contains {
+			continue
+		}
+		for _, c := range f.conditions {
+			if !c(p.Remote) {
+				continue list
+			}
 		}
+		filtered = append(filtered, p)
 	}
-	return append(head, tail...)
+	return
 }
 
 func (f *Filter) AddPeers(n []*peer.Peer) {
@@ -66,6 +61,10 @@ func (f *Filter) RemovePeer(peer peer.ID) {
 	f.lock.Unlock()
 }
 
+func (f *Filter) AddCondition(c func(p *peer.Peer) bool) {
+	f.conditions = append(f.conditions, c)
+}
+
 func (f *Filter) Clean() {
 	f.lock.Lock()
 	f.internal = make(map[peer.ID]bool)
diff --git a/plugins/autopeering/autopeering.go b/plugins/autopeering/autopeering.go
index 5f2ee94b647742cbe55176316f9bb483a693adb7..2d578fc9fbbe41bf8ed96bc74fd24ba0a76febe4 100644
--- a/plugins/autopeering/autopeering.go
+++ b/plugins/autopeering/autopeering.go
@@ -48,12 +48,32 @@ func configureAP() {
 	// enable peer selection only when gossip is enabled
 	if !node.IsSkipped(gossip.PLUGIN) {
 		Selection = selection.New(local.GetInstance(), Discovery, selection.Config{
-			Log:              log.Named("sel"),
-			RequiredServices: []service.Key{service.GossipKey},
+			Log:               log.Named("sel"),
+			NeighborValidator: selection.ValidatorFunc(isValidNeighbor),
 		})
 	}
 }
 
+// isValidNeighbor checks whether a peer is a valid neighbor.
+func isValidNeighbor(p *peer.Peer) bool {
+	// gossip must be supported
+	gossipAddr := p.Services().Get(service.GossipKey)
+	if gossipAddr == nil {
+		return false
+	}
+	// the host for the gossip and peering service must be identical
+	gossipHost, _, err := net.SplitHostPort(gossipAddr.String())
+	if err != nil {
+		return false
+	}
+	peeringAddr := p.Services().Get(service.PeeringKey)
+	peeringHost, _, err := net.SplitHostPort(peeringAddr.String())
+	if err != nil {
+		return false
+	}
+	return gossipHost == peeringHost
+}
+
 func start(shutdownSignal <-chan struct{}) {
 	defer log.Info("Stopping " + name + " ... done")