diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php
index fcd8307..5d40cc4 100644
--- src/bp-members/bp-members-functions.php
+++ src/bp-members/bp-members-functions.php
@@ -2523,6 +2523,22 @@ function bp_register_member_type( $member_type, $args = array() ) {
 
 	$member_type = sanitize_key( $member_type );
 
+	/**
+	 * Filters the list of illegal member type names.
+	 *
+	 * - 'any' is a special pseudo-type, used to retrieve items unrestricted by member type.
+	 * - 'null' is a special pseudo-type, representing users without any type.
+	 * - '_none' is used internally to denote an item that should not apply to any membe types.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @param array $illegal_names Array of illegal names.
+	 */
+	$illegal_names = apply_filters( 'bp_member_type_illegal_names', array( 'any', 'null', '_none' ));
+	if ( in_array( $member_type, $illegal_names, true ) ) {
+		return new WP_Error( 'bp_member_type_illegal_name', __( 'You may not register a member type with this name.', 'buddypress' ), $member_type );
+	}
+
 	// Store the post type name as data in the object (not just as the array key).
 	$r['name'] = $member_type;
 
diff --git src/bp-xprofile/admin/css/admin.css src/bp-xprofile/admin/css/admin.css
index f7374f7..a1b3170 100644
--- src/bp-xprofile/admin/css/admin.css
+++ src/bp-xprofile/admin/css/admin.css
@@ -274,3 +274,13 @@ textarea#group_description {
 #bp-xprofile-add-field #post-body-content {
 	margin-bottom: 0;
 }
+
+span.member-type-none-notice,
+p.member-type-none-notice {
+	color: #f00;	
+}
+
+.hide {
+	display: none;
+	visibility: hidden;
+}
diff --git src/bp-xprofile/admin/js/admin.js src/bp-xprofile/admin/js/admin.js
index 31ae10c..11e9e33 100644
--- src/bp-xprofile/admin/js/admin.js
+++ src/bp-xprofile/admin/js/admin.js
@@ -96,6 +96,34 @@ function hide( id ) {
 	document.getElementById( field_id ).value = '';
 }
 
+/**
+ * @summary Toggle "no member type" notice.
+ *
+ * @since BuddyPress (2.4.0)
+ */
+function toggle_no_member_type_notice() {
+	var $member_type_checkboxes = jQuery( 'input.member-type-selector' );
+
+	// No checkboxes? Nothing to do.
+	if ( ! $member_type_checkboxes.length ) {
+		return;
+	}
+
+	var has_checked = false;
+	$member_type_checkboxes.each( function() {
+		if ( jQuery( this ).is( ':checked' ) ) {
+			has_checked = true;
+			return false;
+		}
+	} );
+
+	if ( has_checked ) {
+		jQuery( 'p.member-type-none-notice' ).addClass( 'hide' );
+	} else {
+		jQuery( 'p.member-type-none-notice' ).removeClass( 'hide' );
+	}
+}
+
 var fixHelper = function(e, ui) {
 	ui.children().each(function() {
 		jQuery(this).width( jQuery(this).width() );
@@ -152,6 +180,11 @@ jQuery( document ).ready( function() {
 	// Set focus in Field Title, if we're on the right page
 	jQuery( '#bp-xprofile-add-field #title' ).focus();
 
+	toggle_no_member_type_notice();
+	jQuery( 'input.member-type-selector' ).on( 'change', function() {
+		toggle_no_member_type_notice();
+	} );
+
 	// Set up deleting options ajax
 	jQuery( 'a.ajax-option-delete' ).on( 'click', function() {
 		var theId = this.id.split( '-' );
diff --git src/bp-xprofile/bp-xprofile-admin.php src/bp-xprofile/bp-xprofile-admin.php
index 55c4b6d..3d15245 100644
--- src/bp-xprofile/bp-xprofile-admin.php
+++ src/bp-xprofile/bp-xprofile-admin.php
@@ -361,6 +361,16 @@ function xprofile_admin_manage_field( $group_id, $field_id = null ) {
 					bp_update_option( 'bp-xprofile-fullname-field-name', $field->name );
 				}
 
+				// Set member types.
+				if ( isset( $_POST['has-member-types'] ) ) {
+					$member_types = array();
+					if ( isset( $_POST['member-types'] ) ) {
+						$member_types = stripslashes_deep( $_POST['member-types'] );
+					}
+
+					$field->set_member_types( $member_types );
+				}
+
 				// Validate default visibility
 				if ( ! empty( $_POST['default-visibility'] ) && in_array( $_POST['default-visibility'], wp_list_pluck( bp_xprofile_get_visibility_levels(), 'id' ) ) ) {
 					bp_xprofile_update_field_meta( $field_id, 'default_visibility', $_POST['default-visibility'] );
@@ -499,6 +509,7 @@ function xprofile_admin_field( $admin_field, $admin_group, $class = '' ) {
 				<?php if ( empty( $field->can_delete )                                    ) : ?><?php esc_html_e( '(Primary)',  'buddypress' ); endif; ?>
 				<?php if ( bp_get_the_profile_field_is_required()                         ) : ?><?php esc_html_e( '(Required)', 'buddypress' ); endif; ?>
 				<?php if ( bp_xprofile_get_meta( $field->id, 'field', 'signup_position' ) ) : ?><?php esc_html_e( '(Sign-up)',  'buddypress' ); endif; ?>
+				<?php if ( bp_get_member_types() ) : echo $field->get_member_type_label(); endif; ?>
 
 				<?php
 
diff --git src/bp-xprofile/bp-xprofile-cache.php src/bp-xprofile/bp-xprofile-cache.php
index 07e0ec1..a12a98e 100644
--- src/bp-xprofile/bp-xprofile-cache.php
+++ src/bp-xprofile/bp-xprofile-cache.php
@@ -236,6 +236,16 @@ add_action( 'xprofile_fields_saved_field',   'xprofile_clear_profile_field_objec
 add_action( 'xprofile_fields_deleted_field', 'xprofile_clear_profile_field_object_cache' );
 
 /**
+ * Clear member_type cache when a field's member types are updated.
+ *
+ * @since BuddyPress (2.4.0)
+ */
+function bp_xprofile_clear_member_type_cache() {
+	wp_cache_delete( 'field_member_types', 'bp_xprofile' );
+}
+add_action( 'bp_xprofile_field_set_member_type', 'bp_xprofile_clear_member_type_cache' );
+
+/**
  * Clear caches when a user's updates a field data object.
  *
  * @since BuddyPress (2.0.0)
diff --git src/bp-xprofile/bp-xprofile-template.php src/bp-xprofile/bp-xprofile-template.php
index 298b69b..c66cda4 100644
--- src/bp-xprofile/bp-xprofile-template.php
+++ src/bp-xprofile/bp-xprofile-template.php
@@ -153,6 +153,7 @@ class BP_XProfile_Data_Template {
 		$r = wp_parse_args( $args, array(
 			'profile_group_id'       => false,
 			'user_id'                => false,
+			'member_type'            => 'any',
 			'hide_empty_groups'      => false,
 			'hide_empty_fields'      => false,
 			'fetch_fields'           => false,
@@ -333,6 +334,7 @@ function bp_has_profile( $args = '' ) {
 	// Parse arguments
 	$r = bp_parse_args( $args, array(
 		'user_id'                => bp_displayed_user_id(),
+		'member_type'            => 'any',
 		'profile_group_id'       => false,
 		'hide_empty_groups'      => true,
 		'hide_empty_fields'      => $hide_empty_fields_default,
diff --git src/bp-xprofile/classes/class-bp-xprofile-field.php src/bp-xprofile/classes/class-bp-xprofile-field.php
index 4d08bca..9d598e3 100644
--- src/bp-xprofile/classes/class-bp-xprofile-field.php
+++ src/bp-xprofile/classes/class-bp-xprofile-field.php
@@ -124,6 +124,15 @@ class BP_XProfile_Field {
 	public $data;
 
 	/**
+	 * Member types to which the profile field should be applied.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 * @access protected
+	 * @var array Array of member types.
+	 */
+	protected $member_types;
+
+	/**
 	 * Initialize and/or populate profile field
 	 *
 	 * @since BuddyPress (1.1.0)
@@ -457,6 +466,171 @@ class BP_XProfile_Field {
 		$wpdb->query( $sql );
 	}
 
+	/**
+	 * Get the member types to which this field should be available.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 */
+	public function get_member_types() {
+		if ( ! is_null( $this->member_types ) ) {
+			return $this->member_types;
+		}
+
+		$raw_types = bp_xprofile_get_meta( $this->id, 'field', 'member_type', false );
+
+		// If `$raw_types` is not an array, it probably means this is a new field (id=0).
+		if ( ! is_array( $raw_types ) ) {
+			$raw_types = array();
+		}
+
+		// If '_none' is found in the array, it overrides all types.
+		$types = array();
+		if ( ! in_array( '_none', $raw_types ) ) {
+			$registered_types = bp_get_member_types();
+
+			// Eliminate invalid member types saved in the database.
+			foreach ( $raw_types as $raw_type ) {
+				// 'null' is a special case - it represents users without a type.
+				if ( 'null' === $raw_type || isset( $registered_types[ $raw_type ] ) ) {
+					$types[] = $raw_type;
+				}
+			}
+
+			// If no member types have been saved, intepret as *all* member types.
+			if ( empty( $types ) ) {
+				$types = array_values( $registered_types );
+
+				// + the "null" type, ie users without a type.
+				$types[] = 'null';
+			}
+		}
+
+		/**
+		 * Filters the member types to which an XProfile object should be applied.
+		 *
+		 * @since BuddyPress (2.4.0)
+		 *
+		 * @param array             $types Member types.
+		 * @param BP_XProfile_Field $field Field object.
+		 */
+		$this->member_types = apply_filters( 'bp_xprofile_field_member_types', $types, $this );
+
+		return $this->member_types;
+	}
+
+	/**
+	 * Set the member types for this field.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @param array $member_types Array of member types.
+	 * @param bool  $append       Whether to append to existing member types. If false, all existing member type
+	 *                            associations will be deleted before adding your `$member_types`. Default false.
+	 * @return array Member types for the current field, after being saved.
+	 */
+	public function set_member_types( $member_types, $append = false ) {
+		// Unset invalid member types.
+		$types = array();
+		foreach ( $member_types as $member_type ) {
+			// 'null' is a special case - it represents users without a type.
+			if ( 'null' === $member_type || bp_get_member_type_object( $member_type ) ) {
+				$types[] = $member_type;
+			}
+		}
+
+		// When `$append` is false, delete all existing types before adding new ones.
+		if ( ! $append ) {
+			bp_xprofile_delete_meta( $this->id, 'field', 'member_type' );
+
+			/*
+			 * We interpret an empty array as disassociating the field from all types. This is
+			 * represented internally with the '_none' flag.
+			 */
+			if ( empty( $types ) ) {
+				bp_xprofile_add_meta( $this->id, 'field', 'member_type', '_none' );
+			}
+		}
+
+		// "All types" is represented in the database with no meta entries.
+		$registered_types = bp_get_member_types();
+		$rtypes = array_values( $registered_types );
+		$rtypes[] = 'null';
+
+		sort( $types );
+		sort( $rtypes );
+
+		if ( $types !== $rtypes ) {
+			// Save new types.
+			foreach ( $types as $type ) {
+				bp_xprofile_add_meta( $this->id, 'field', 'member_type', $type );
+			}
+		}
+
+		// Reset internal cache of member types.
+		$this->member_types = null;
+
+		/**
+		 * Fires after a field's member types have been updated.
+		 *
+		 * @since BuddyPress (2.4.0)
+		 *
+		 * @param BP_XProfile_Field $field Field object.
+		 */
+		do_action( 'bp_xprofile_field_set_member_type', $this );
+
+		// Refetch fresh items from the database.
+		return $this->get_member_types();
+	}
+
+	/**
+	 * Get a label representing the field's member types.
+	 *
+	 * This is displayed alongside the field's name on the Profile Fields Dashboard panel.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @return string
+	 */
+	public function get_member_type_label() {
+		// Field 1 never gets a label.
+		if ( 1 == $this->id ) {
+			return '';
+		}
+
+		// Return an empty string if no member types are registered.
+		$all_types = bp_get_member_types();
+		if ( empty( $all_types ) ) {
+			return '';
+		}
+
+		$member_types = $this->get_member_types();
+
+		// If the field applies to all member types, show no message. 
+		$all_types[] = 'null';
+		if ( array_values( $all_types ) == $member_types ) {
+			return '';
+		}
+
+		$label = '';
+		if ( ! empty( $member_types ) ) {
+			$member_type_labels = array();
+			foreach ( $member_types as $member_type ) {
+				if ( 'null' === $member_type ) {
+					$member_type_labels[] = __( 'Users with no member type', 'buddypress' );
+				} else {
+					$mt_obj = bp_get_member_type_object( $member_type );
+					$member_type_labels[] = $mt_obj->labels['name'];
+				}
+			}
+
+			$label = sprintf( __( '(Member types: %s)', 'buddypress' ), implode( ', ', array_map( 'esc_html', $member_type_labels ) ) );
+		} else {
+			$label = '<span class="member-type-none-notice">' . __( '(Unavailable to all member types)', 'buddypress' ) . '</span>';
+		}
+
+		return $label;
+	}
+
 	/** Static Methods ********************************************************/
 
 	public static function get_type( $field_id = 0 ) {
@@ -574,6 +748,73 @@ class BP_XProfile_Field {
 	}
 
 	/**
+	 * Get the IDs of fields applicable for a given member type or array of member types.
+	 *
+	 * @todo Improved cache support.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @param string|array $member_types Member type or array of member types.
+	 */
+	public static function get_fields_for_member_type( $member_types ) {
+		global $wpdb;
+
+		$bp = buddypress();
+
+		if ( ! is_array( $member_types ) ) {
+			$member_types = array( $member_types );
+		}
+
+		$fields = array();
+
+		// Pull up all recorded field member type data.
+		$mt_meta = wp_cache_get( 'field_member_types', 'bp_xprofile' );
+		if ( false === $mt_meta ) {
+			$mt_meta = $wpdb->get_results( "SELECT object_id, meta_value FROM {$bp->profile->table_name_meta} WHERE meta_key = 'member_type' AND object_type = 'field'" );
+			wp_cache_set( 'field_member_types', $mt_meta, 'bp_xprofile' );
+		}
+
+		// Keep track of all fields with recorded member_type metadata.
+		$all_recorded_field_ids = wp_list_pluck( $mt_meta, 'object_id' );
+
+		// Sort member_type matches in arrays, keyed by field_id.
+		foreach ( $mt_meta as $_mt_meta ) {
+			if ( ! isset( $fields[ $_mt_meta->object_id ] ) ) {
+				$fields[ $_mt_meta->object_id ] = array();
+			}
+
+			$fields[ $_mt_meta->object_id ][] = $_mt_meta->meta_value;
+		}
+
+		// Filter out fields that don't match any passed types, or those marked _none.
+		foreach ( $fields as $field_id => $field_types ) {
+			if ( ! array_intersect( $field_types, $member_types ) ) {
+				unset( $fields[ $field_id ] );
+			}
+		}
+
+		// Any fields with no member_type metadata are available to all member types.
+		if ( ! in_array( '_none', $member_types ) ) {
+			if ( ! empty( $all_recorded_field_ids ) ) {
+				$all_recorded_field_ids_sql = implode( ',', array_map( 'absint', $all_recorded_field_ids ) );
+				$unrestricted_field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields} WHERE id NOT IN ({$all_recorded_field_ids_sql})" );
+			} else {
+				$unrestricted_field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields}" );
+			}
+
+			$all_member_types   = bp_get_member_types();
+			$all_member_types   = array_values( $all_member_types );
+			$all_member_types[] = 'null';
+
+			foreach ( $unrestricted_field_ids as $unrestricted_field_id ) {
+				$fields[ $unrestricted_field_id ] = $all_member_types;
+			}
+		}
+
+		return $fields;
+	}
+
+	/**
 	 * Validate form field data on sumbission
 	 *
 	 * @since BuddyPress (2.2.0)
@@ -718,6 +959,9 @@ class BP_XProfile_Field {
 							// Output the required metabox
 							$this->required_metabox();
 
+							// Output the Member Types metabox.
+							$this->member_type_metabox();
+
 							// Output the field visibility metaboxes
 							$this->visibility_metabox();
 
@@ -864,6 +1108,59 @@ class BP_XProfile_Field {
 	}
 
 	/**
+	 * Private method used to output field Member Type metabox.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 */
+	private function member_type_metabox() {
+
+		// The primary field is for all, so bail.
+		if ( 1 === (int) $this->id ) {
+			return;
+		}
+
+		// Bail when no member types are registered.
+		if ( ! $member_types = bp_get_member_types( array(), 'objects' ) ) {
+			return;
+		}
+
+		$field_member_types = $this->get_member_types();
+
+		?>
+
+		<div id="member-types-div" class="postbox">
+			<h3><?php _e( 'Member Types', 'buddypress' ); ?></h3>
+			<div class="inside">
+				<p class="description"><?php _e( 'This field should be available to:', 'buddypress' ); ?></p>
+
+				<ul>
+					<?php foreach ( $member_types as $member_type ) : ?>
+					<li>
+						<label>
+							<input name="member-types[]" class="member-type-selector" type="checkbox" value="<?php echo $member_type->name; ?>" <?php checked( in_array( $member_type->name, $field_member_types ) ); ?>/>
+							<?php echo $member_type->labels['name']; ?>
+						</label>
+					</li>
+					<?php endforeach; ?>
+
+					<li>
+						<label>
+							<input name="member-types[]" class="member-type-selector" type="checkbox" value="null" <?php checked( in_array( 'null', $field_member_types ) ); ?>/>
+							<?php _e( 'Users with no member type', 'buddypress' ); ?>
+						</label>
+					</li>
+
+				</ul>
+				<p class="description member-type-none-notice<?php if ( ! empty( $field_member_types ) ) : ?> hide<?php endif; ?>"><?php _e( 'Fields with no member types are unavailable to all users.', 'buddypress' ) ?></p>
+			</div>
+
+			<input type="hidden" name="has-member-types" value="1" />
+		</div>
+
+		<?php
+	}
+
+	/**
 	 * Private method used to output field visibility metaboxes
 	 *
 	 * @since BuddyPress (2.3.0)
diff --git src/bp-xprofile/classes/class-bp-xprofile-group.php src/bp-xprofile/classes/class-bp-xprofile-group.php
index 7d85a14..024b8df 100644
--- src/bp-xprofile/classes/class-bp-xprofile-group.php
+++ src/bp-xprofile/classes/class-bp-xprofile-group.php
@@ -232,6 +232,11 @@ class BP_XProfile_Group {
 	 *	@type int   $profile_group_id  Limit results to a single profile group.
 	 *      @type int   $user_id           Required if you want to load a specific user's data.
 	 *                                     Default: displayed user's ID.
+	 *      @type array|string $member_type Limit fields by those restricted to a given member type, or array of
+	 *                                      member types. If `$user_id` is provided, the value of `$member_type`
+	 *                                      will be overridden by the member types of the provided user. The
+	 *                                      special value of 'any' will return only those fields that are
+	 *                                      unrestricted by member type - i.e., those applicable to any type.
 	 *      @type bool  $hide_empty_groups True to hide groups that don't have any fields. Default: false.
 	 *	@type bool  $hide_empty_fields True to hide fields where the user has not provided data. Default: false.
 	 *      @type bool  $fetch_fields      Whether to fetch each group's fields. Default: false.
@@ -251,6 +256,7 @@ class BP_XProfile_Group {
 		$r = wp_parse_args( $args, array(
 			'profile_group_id'       => false,
 			'user_id'                => bp_displayed_user_id(),
+			'member_type'            => false,
 			'hide_empty_groups'      => false,
 			'hide_empty_fields'      => false,
 			'fetch_fields'           => false,
@@ -318,15 +324,41 @@ class BP_XProfile_Group {
 		$exclude_fields_cs  = array_merge( $exclude_fields_cs, $hidden_user_fields );
 		$exclude_fields_cs  = implode( ',', $exclude_fields_cs );
 
-		// Setup IN query for field IDs
+		// Set up NOT IN query for excluded field IDs.
 		if ( ! empty( $exclude_fields_cs ) ) {
 			$exclude_fields_sql = "AND id NOT IN ({$exclude_fields_cs})";
 		} else {
 			$exclude_fields_sql = '';
 		}
 
+		// Set up IN query for included field IDs.
+		$include_field_ids = array();
+
+		// Member-type restrictions.
+		if ( bp_get_member_types() ) {
+			if ( $r['user_id'] || false !== $r['member_type'] ) {
+				$member_types = $r['member_type'];
+				if ( $r['user_id'] ) {
+					$member_types = bp_get_member_type( $r['user_id'], false );
+					if ( empty( $member_types ) ) {
+						$member_types = array( 'null' );
+					}
+				}
+
+				$member_types_fields = BP_XProfile_Field::get_fields_for_member_type( $member_types );
+				$include_field_ids += array_keys( $member_types_fields );
+			}
+		}
+
+		$in_sql = '';
+		if ( ! empty( $include_field_ids ) ) {
+			$include_field_ids_cs = implode( ',', array_map( 'intval', $include_field_ids ) );
+			$in_sql = " AND id IN ({$include_field_ids_cs}) ";
+		}
+
 		// Fetch the fields
-		$fields    = $wpdb->get_results( "SELECT id, name, description, type, group_id, is_required FROM {$bp->profile->table_name_fields} WHERE group_id IN ( {$group_ids_in} ) AND parent_id = 0 {$exclude_fields_sql} ORDER BY field_order" );
+		$fields = $wpdb->get_results( "SELECT id, name, description, type, group_id, is_required FROM {$bp->profile->table_name_fields} WHERE group_id IN ( {$group_ids_in} ) AND parent_id = 0 {$exclude_fields_sql} {$in_sql} ORDER BY field_order" );
+
 		$field_ids = wp_list_pluck( $fields, 'id' );
 
 		// Store field IDs for meta cache priming
diff --git tests/phpunit/testcases/members/types.php tests/phpunit/testcases/members/types.php
index 249049b..91dccd0 100644
--- tests/phpunit/testcases/members/types.php
+++ tests/phpunit/testcases/members/types.php
@@ -21,6 +21,22 @@ class BP_Tests_Members_Types extends BP_UnitTestCase {
 	}
 
 	/**
+	 * @dataProvider illegal_names
+	 * @ticket BP5192
+	 */
+	public function test_illegal_names( $name ) {
+		$this->assertWPError( bp_register_member_type( $name ) );
+	}
+
+	public function illegal_names() {
+		return array(
+			array( 'any' ),
+			array( 'null' ),
+			array( '_none' ),
+		);
+	}
+
+	/**
 	 * @ticket BP6139
 	 */
 	public function test_bp_register_member_type_should_sanitize_member_type_key() {
diff --git tests/phpunit/testcases/xprofile/BP_XProfile_Field/member_types.php tests/phpunit/testcases/xprofile/BP_XProfile_Field/member_types.php
new file mode 100644
index 0000000..6a92d4e
--- /dev/null
+++ tests/phpunit/testcases/xprofile/BP_XProfile_Field/member_types.php
@@ -0,0 +1,186 @@
+<?php
+
+/**
+ * @group member_types
+ * @group xprofile
+ * @ticket BP5192
+ */
+class BP_Tests_XProfile_BpXprofileField_MemberTypes extends BP_UnitTestCase {
+	protected $field_group_id;
+	protected $field_id;
+	protected $field;
+
+	public function setUp() {
+		parent::setUp();
+		bp_register_member_type( 'foo' );
+		bp_register_member_type( 'bar' );
+
+		$this->field_group_id = $this->factory->xprofile_group->create();
+		$this->field_id = $this->factory->xprofile_field->create( array( 'field_group_id' => $this->field_group_id ) );
+		$this->field = new BP_XProfile_Field( $this->field_id );
+	}
+
+	public function tearDown() {
+		buddypress()->members->types = array();
+		parent::tearDown();
+	}
+
+	public function test_get_single_member_type() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		$this->assertEqualSets( array( 'foo' ), $this->field->get_member_types() );
+	}
+
+	public function test_get_multiple_member_types() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'bar' );
+		$this->assertEqualSets( array( 'foo', 'bar' ), $this->field->get_member_types() );
+	}
+
+	public function test_invalid_member_types_should_not_be_returned() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'phony' );
+		$this->assertEquals( array( 'foo' ), $this->field->get_member_types() );
+	}
+
+	public function test_when_no_stored_types_are_found_all_registered_member_types_as_well_as_null_type_should_be_returned() {
+		$this->assertEqualSets( array( 'null', 'foo', 'bar' ), $this->field->get_member_types() );
+	}
+
+	public function test__none_meta_should_result_in_empty_array() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', '_none' );
+		$this->assertEquals( array(), $this->field->get_member_types() );
+	}
+
+	public function test__none_meta_should_override_other_values() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', '_none' );
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		$this->assertEquals( array(), $this->field->get_member_types() );
+	}
+
+	public function test_set_should_not_append_by_default() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		$this->assertEquals( array( 'bar' ), $this->field->set_member_types( array( 'bar' ) ) );
+	}
+
+	public function test_set_should_not_append_when_append_is_set_to_false() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		$this->assertEquals( array( 'bar' ), $this->field->set_member_types( array( 'bar', false ) ) );
+	}
+
+	public function test_set_should_append_when_append_is_set_to_true() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		$this->assertEqualSets( array( 'foo', 'bar' ), $this->field->set_member_types( array( 'bar' ), true ) );
+	}
+
+	public function test_set_empty_array_with_append_true_should_have_no_effect_on_saved_types() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		$this->assertEqualSets( array( 'foo' ), $this->field->set_member_types( array(), true ) );
+	}
+
+	public function test_set_empty_array_with_append_false_should_result_in_field_being_associated_with_no_member_types() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		$this->assertEqualSets( array(), $this->field->set_member_types( array() ) );
+	}
+
+	public function test_set_should_interpret_null_flag_properly() {
+		$this->assertEqualSets( array( 'null' ), $this->field->set_member_types( array( 'null' ) ) );
+	}
+
+	public function test_set_all_types_plus_null_should_result_in_nothing_stored_in_db() {
+		$types = array( 'null', 'foo', 'bar' );
+		$this->assertEqualSets( $types, $this->field->set_member_types( $types ) );
+
+		$types_db = bp_xprofile_get_meta( $this->field_id, 'field', 'member_type', false );
+		$this->assertEqualSets( array(), $types_db );
+	}
+
+	public function test_get_fields_for_member_type_should_get_field_with_explicit_member_type() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		$found = BP_XProfile_Field::get_fields_for_member_type( 'foo' );
+		$this->assertEqualSets( array( 1, $this->field_id ), array_keys( $found ) );
+	}
+
+	public function test_get_fields_for_member_type_should_ignore_field_that_applies_to_no_member_types() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', '_none' );
+		$found = BP_XProfile_Field::get_fields_for_member_type( 'foo' );
+		$this->assertEqualSets( array( 1 ), array_keys( $found ) );
+	}
+
+	public function test_get_fields_for_member_type_should_ignore_field_that_applies_to_different_member_types() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'bar' );
+		$found = BP_XProfile_Field::get_fields_for_member_type( 'foo' );
+		$this->assertEqualSets( array( 1 ), array_keys( $found ) );
+	}
+
+	public function test_get_fields_for_member_type_should_include_fields_with_no_member_type_restrictions() {
+		// A field with no member_type metadata applies to all member types.
+		$found = BP_XProfile_Field::get_fields_for_member_type( 'foo' );
+		$this->assertEqualSets( array( 1, $this->field_id ), array_keys( $found ) );
+	}
+
+	public function test_passing_member_type_any_to_get_fields_for_member_type_should_return_unrestricted_fields() {
+		$found = BP_XProfile_Field::get_fields_for_member_type( '' );
+		$this->assertEqualSets( array( 1, $this->field_id ), array_keys( $found ) );
+	}
+
+	public function test_passing_empty_member_type_to_get_fields_for_member_type_should_return_unrestricted_fields() {
+		$found = BP_XProfile_Field::get_fields_for_member_type( 'any' );
+		$this->assertEqualSets( array( 1, $this->field_id ), array_keys( $found ) );
+	}
+
+	public function test_passing_member_type_none_to_get_fields_for_member_type_should_return_fields_unavailable_to_all_member_types() {
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', '_none' );
+		$found = BP_XProfile_Field::get_fields_for_member_type( '_none' );
+		$this->assertEqualSets( array( $this->field_id ), array_keys( $found ) );
+	}
+
+	public function test_get_fields_for_member_type_should_accept_an_array_of_member_types() {
+		$f2 = $this->factory->xprofile_field->create( array( 'field_group_id' => $this->field_group_id ) );
+		bp_xprofile_add_meta( $this->field_id, 'field', 'member_type', 'foo' );
+		bp_xprofile_add_meta( $f2, 'field', 'member_type', 'bar' );
+
+		$found = BP_XProfile_Field::get_fields_for_member_type( array( 'foo', 'bar' ) );
+		$this->assertEqualSets( array( 1, $this->field_id, $f2 ), array_keys( $found ) );
+	}
+
+	/**
+	 * @group cache
+	 */
+	public function test_get_fields_for_member_type_should_fetch_restricted_fields_from_cache() {
+		global $wpdb;
+
+		$this->field->set_member_types( array( 'foo' ) );
+
+		// Prime cache.
+		BP_XProfile_Field::get_fields_for_member_type( 'foo' );
+
+		$num_queries = $wpdb->num_queries;
+
+		BP_XProfile_Field::get_fields_for_member_type( 'foo' );
+
+		// get_fields_for_member_type() always does at least one query.
+		$num_queries++;
+		$this->assertSame( $num_queries, $wpdb->num_queries );
+	}
+
+	/**
+	 * @group cache
+	 */
+	public function test_get_fields_for_member_type_should_skip_cache_after_a_fields_member_type_is_modified() {
+		global $wpdb;
+
+		$this->field->set_member_types( array( 'foo' ) );
+
+		// Prime cache.
+		BP_XProfile_Field::get_fields_for_member_type( 'foo' );
+
+		$num_queries = $wpdb->num_queries;
+
+		$this->field->set_member_types( array( 'none' ) );
+
+		$found = BP_XProfile_Field::get_fields_for_member_type( 'foo' );
+
+		$this->assertTrue( $num_queries + 2 <= $wpdb->num_queries );
+		$this->assertEqualSets( array( 1 ), array_keys( $found ) );
+	}
+}
diff --git tests/phpunit/testcases/xprofile/class-bp-xprofile-group.php tests/phpunit/testcases/xprofile/class-bp-xprofile-group.php
index 6a0492b..7841b67 100644
--- tests/phpunit/testcases/xprofile/class-bp-xprofile-group.php
+++ tests/phpunit/testcases/xprofile/class-bp-xprofile-group.php
@@ -113,6 +113,281 @@ class BP_Tests_BP_XProfile_Group extends BP_UnitTestCase {
 	}
 
 	/**
+	 * @group member_types
+	 * @ticket BP5192
+	 */
+	public function test_member_type_restrictions_should_be_ignored_when_user_id_is_null_and_member_type_is_not_explicitly_provided() {
+		$g = $this->factory->xprofile_group->create();
+		$f = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		bp_register_member_type( 'foo' );
+
+		$field = new BP_XProfile_Field( $f );
+		$field->set_member_types( array( 'foo' ) );
+
+		$found_groups = BP_XProfile_Group::get( array(
+			'user_id' => false,
+			'fetch_fields' => true,
+		) );
+
+		// The groups aren't indexed, so we have to go looking for it.
+		foreach ( $found_groups as $fg ) {
+			if ( $g == $fg->id ) {
+				$the_group = $fg;
+			}
+		}
+
+		$this->assertContains( $f, wp_list_pluck( $the_group->fields, 'id' ) );
+	}
+
+	/**
+	 * @group member_types
+	 * @ticket BP5192
+	 */
+	public function test_member_type_restrictions_should_be_ignored_when_user_id_is_0_and_member_type_is_false() {
+		$g = $this->factory->xprofile_group->create();
+		$f = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		bp_register_member_type( 'foo' );
+
+		$field = new BP_XProfile_Field( $f );
+		$field->set_member_types( array( 'foo' ) );
+
+		$found_groups = BP_XProfile_Group::get( array(
+			'user_id' => 0,
+			'member_type' => false,
+			'fetch_fields' => true,
+		) );
+
+		// The groups aren't indexed, so we have to go looking for it.
+		foreach ( $found_groups as $fg ) {
+			if ( $g == $fg->id ) {
+				$the_group = $fg;
+			}
+		}
+
+		$this->assertContains( $f, wp_list_pluck( $the_group->fields, 'id' ) );
+	}
+
+	/**
+	 * @group member_types
+	 * @ticket BP5192
+	 */
+	public function test_member_type_restrictions_should_be_obeyed_for_nonzero_user_id() {
+		$g = $this->factory->xprofile_group->create();
+		$f1 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		$f2 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		$f3 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		$f4 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		bp_register_member_type( 'foo' );
+		bp_register_member_type( 'bar' );
+
+		// Field 1 is visible only to 'foo' users.
+		$field1 = new BP_XProfile_Field( $f1 );
+		$field1->set_member_types( array( 'foo' ) );
+
+		// Field 2 is visible only to 'bar' users.
+		$field2 = new BP_XProfile_Field( $f2 );
+		$field2->set_member_types( array( 'bar' ) );
+
+		// Field 3 is visible to all users (no member type set).
+
+		// Field 4 is visible to no one.
+		$field4 = new BP_XProfile_Field( $f4 );
+		$field4->set_member_types( array() );
+
+		// User is in 'foo', so should have f1 and f3 only.
+		$u = $this->factory->user->create();
+		bp_set_member_type( $u, 'foo' );
+
+		$found_groups = BP_XProfile_Group::get( array(
+			'user_id' => $u,
+			'fetch_fields' => true,
+		) );
+
+		// The groups aren't indexed, so we have to go looking for it.
+		foreach ( $found_groups as $fg ) {
+			if ( $g == $fg->id ) {
+				$the_group = $fg;
+			}
+		}
+
+		$this->assertContains( $f1, wp_list_pluck( $the_group->fields, 'id' ) );
+		$this->assertContains( $f3, wp_list_pluck( $the_group->fields, 'id' ) );
+		$this->assertNotContains( $f2, wp_list_pluck( $the_group->fields, 'id' ) );
+		$this->assertNotContains( $f4, wp_list_pluck( $the_group->fields, 'id' ) );
+	}
+
+	/**
+	 * @group member_types
+	 * @ticket BP5192
+	 */
+	public function test_member_type_restrictions_should_be_obeyed_for_nonzero_user_id_with_no_member_types() {
+		$g = $this->factory->xprofile_group->create();
+		$f1 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		$f2 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		$f3 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		bp_register_member_type( 'foo' );
+		bp_register_member_type( 'bar' );
+
+		// Field 1 is visible only to 'foo' users.
+		$field1 = new BP_XProfile_Field( $f1 );
+		$field1->set_member_types( array( 'foo' ) );
+
+		// Field 2 is visible only to 'null' users.
+		$field2 = new BP_XProfile_Field( $f2 );
+		$field2->set_member_types( array( 'null' ) );
+
+		// Field 3 is visible to all users (no member type set).
+
+		// User has no member types, so should see f2 and f3 .
+		$u = $this->factory->user->create();
+
+		$found_groups = BP_XProfile_Group::get( array(
+			'user_id' => $u,
+			'fetch_fields' => true,
+		) );
+
+		// The groups aren't indexed, so we have to go looking for it.
+		foreach ( $found_groups as $fg ) {
+			if ( $g == $fg->id ) {
+				$the_group = $fg;
+			}
+		}
+
+		$this->assertNotContains( $f1, wp_list_pluck( $the_group->fields, 'id' ) );
+		$this->assertContains( $f2, wp_list_pluck( $the_group->fields, 'id' ) );
+		$this->assertContains( $f3, wp_list_pluck( $the_group->fields, 'id' ) );
+	}
+
+	/**
+	 * @group member_types
+	 * @ticket BP5192
+	 */
+	public function test_member_types_of_provided_user_id_should_take_precedence_over_provided_member_type() {
+		$g = $this->factory->xprofile_group->create();
+		$f1 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		$f2 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		bp_register_member_type( 'foo' );
+		bp_register_member_type( 'bar' );
+
+		$field1 = new BP_XProfile_Field( $f1 );
+		$field1->set_member_types( array( 'foo' ) );
+		$field2 = new BP_XProfile_Field( $f2 );
+		$field2->set_member_types( array( 'bar' ) );
+
+		$u = $this->factory->user->create();
+		bp_set_member_type( $u, 'foo' );
+
+		$found_groups = BP_XProfile_Group::get( array(
+			'user_id' => $u,
+			'member_type' => 'bar',
+			'fetch_fields' => true,
+		) );
+
+		// The groups aren't indexed, so we have to go looking for it.
+		foreach ( $found_groups as $fg ) {
+			if ( $g == $fg->id ) {
+				$the_group = $fg;
+			}
+		}
+
+		$this->assertContains( $f1, wp_list_pluck( $the_group->fields, 'id' ) );
+	}
+
+	/**
+	 * @group member_types
+	 * @ticket BP5192
+	 */
+	public function test_member_type_single_value_should_be_respected() {
+		$g = $this->factory->xprofile_group->create();
+		$f1 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		$f2 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		bp_register_member_type( 'foo' );
+		bp_register_member_type( 'bar' );
+
+		$field1 = new BP_XProfile_Field( $f1 );
+		$field1->set_member_types( array( 'foo' ) );
+		$field2 = new BP_XProfile_Field( $f2 );
+		$field2->set_member_types( array( 'bar' ) );
+
+		$found_groups = BP_XProfile_Group::get( array(
+			'member_type' => 'bar',
+			'fetch_fields' => true,
+		) );
+
+		// The groups aren't indexed, so we have to go looking for it.
+		foreach ( $found_groups as $fg ) {
+			if ( $g == $fg->id ) {
+				$the_group = $fg;
+			}
+		}
+
+		$this->assertNotContains( $f1, wp_list_pluck( $the_group->fields, 'id' ) );
+		$this->assertContains( $f2, wp_list_pluck( $the_group->fields, 'id' ) );
+	}
+
+	/**
+	 * @group member_types
+	 * @ticket BP5192
+	 */
+	public function test_member_type_array_value_should_be_respected() {
+		$g = $this->factory->xprofile_group->create();
+		$f1 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		$f2 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		bp_register_member_type( 'foo' );
+		bp_register_member_type( 'bar' );
+
+		$field1 = new BP_XProfile_Field( $f1 );
+		$field1->set_member_types( array( 'foo' ) );
+		$field2 = new BP_XProfile_Field( $f2 );
+		$field2->set_member_types( array( 'bar' ) );
+
+		$found_groups = BP_XProfile_Group::get( array(
+			'member_type' => array( 'bar' ),
+			'fetch_fields' => true,
+		) );
+
+		// The groups aren't indexed, so we have to go looking for it.
+		foreach ( $found_groups as $fg ) {
+			if ( $g == $fg->id ) {
+				$the_group = $fg;
+			}
+		}
+
+		$this->assertNotContains( $f1, wp_list_pluck( $the_group->fields, 'id' ) );
+		$this->assertContains( $f2, wp_list_pluck( $the_group->fields, 'id' ) );
+	}
+
+	/**
+	 * @group member_types
+	 * @ticket BP5192
+	 */
+	public function test_member_type_null_should_be_respected() {
+		$g = $this->factory->xprofile_group->create();
+		$f1 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		$f2 = $this->factory->xprofile_field->create( array( 'field_group_id' => $g ) );
+		bp_register_member_type( 'foo' );
+		bp_register_member_type( 'bar' );
+
+		$field1 = new BP_XProfile_Field( $f1 );
+		$field1->set_member_types( array( 'foo' ) );
+
+		$found_groups = BP_XProfile_Group::get( array(
+			'member_type' => array( 'null' ),
+			'fetch_fields' => true,
+		) );
+
+		// The groups aren't indexed, so we have to go looking for it.
+		foreach ( $found_groups as $fg ) {
+			if ( $g == $fg->id ) {
+				$the_group = $fg;
+			}
+		}
+
+		$this->assertNotContains( $f1, wp_list_pluck( $the_group->fields, 'id' ) );
+		$this->assertContains( $f2, wp_list_pluck( $the_group->fields, 'id' ) );
+	}
+
+	/**
 	 * @group save_xprofile_group_name
 	 */
 	public function test_save_xprofile_group_name() {
