Index: wp-includes/js/media-views.js
===================================================================
--- wp-includes/js/media-views.js	(revision 23060)
+++ wp-includes/js/media-views.js	(working copy)
@@ -1558,6 +1558,10 @@
 					multiple:   options.multiple ? 'reset' : false,
 					editable:   true,
 
+					// If the user isn't allowed to edit fields,
+					// can they still edit it locally?
+					allowLocalEdits: true,
+
 					// Show the attachment display settings.
 					displaySettings: true,
 					// Update user settings when users adjust the
@@ -2816,6 +2820,9 @@
 				options.can.save = !! options.nonces.update;
 			}
 
+			if ( this.controller.state().get('allowLocalEdits') )
+				options.allowLocalEdits = true;
+
 			this.views.detach();
 			this.$el.html( this.template( options ) );
 
Index: wp-includes/media.php
===================================================================
--- wp-includes/media.php	(revision 23061)
+++ wp-includes/media.php	(working copy)
@@ -1658,10 +1658,12 @@
 				<a class="check" href="#" title="<?php _e('Deselect'); ?>"><div class="media-modal-icon"></div></a>
 			<# } #>
 		</div>
-		<# if ( data.describe ) { #>
+		<#
+		var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly';
+		if ( data.describe ) { #>
 			<# if ( 'image' === data.type ) { #>
 				<input type="text" value="{{ data.caption }}" class="describe" data-setting="caption"
-					placeholder="<?php esc_attr_e('Describe this image&hellip;'); ?>" />
+					placeholder="<?php esc_attr_e('Describe this image&hellip;'); ?>" {{ maybeReadOnly }} />
 			<# } else { #>
 				<input type="text" value="{{ data.title }}" class="describe" data-setting="title"
 					<# if ( 'video' === data.type ) { #>
@@ -1670,7 +1672,7 @@
 						placeholder="<?php esc_attr_e('Describe this audio file&hellip;'); ?>"
 					<# } else { #>
 						placeholder="<?php esc_attr_e('Describe this media file&hellip;'); ?>"
-					<# } #> />
+					<# } #> {{ maybeReadOnly }} />
 			<# } #>
 		<# } #>
 	</script>
@@ -1713,25 +1715,27 @@
 			</div>
 		</div>
 
-		<# if ( 'image' === data.type ) { #>
+		<#
+		var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly';
+		if ( 'image' === data.type ) { #>
 			<label class="setting" data-setting="title">
 				<span><?php _e('Title'); ?></span>
-				<input type="text" value="{{ data.title }}" />
+				<input type="text" value="{{ data.title }}" {{ maybeReadOnly }} />
 			</label>
 			<label class="setting" data-setting="caption">
 				<span><?php _e('Caption'); ?></span>
-				<textarea
+				<textarea {{ maybeReadOnly }}
 					placeholder="<?php esc_attr_e('Describe this image&hellip;'); ?>"
 					>{{ data.caption }}</textarea>
 			</label>
 			<label class="setting" data-setting="alt">
 				<span><?php _e('Alt Text'); ?></span>
-				<input type="text" value="{{ data.alt }}" />
+				<input type="text" value="{{ data.alt }}" {{ maybeReadOnly }} />
 			</label>
 		<# } else { #>
 			<label class="setting" data-setting="title">
 				<span><?php _e('Title'); ?></span>
-				<input type="text" value="{{ data.title }}"
+				<input type="text" value="{{ data.title }}" {{ maybeReadOnly }}
 				<# if ( 'video' === data.type ) { #>
 					placeholder="<?php esc_attr_e('Describe this video&hellip;'); ?>"
 				<# } else if ( 'audio' === data.type ) { #>
Index: wp-admin/includes/media.php
===================================================================
--- wp-admin/includes/media.php	(revision 23060)
+++ wp-admin/includes/media.php	(working copy)
@@ -1290,6 +1290,8 @@
 		'description' => false,
 	);
 
+	$user_can_edit = current_user_can( 'edit_post', $attachment_id );
+
 	$args = wp_parse_args( $args, $default_args );
 	$args = apply_filters( 'get_media_item_args', $args );
 
@@ -1314,6 +1316,7 @@
 			foreach ( $terms as $term )
 				$values[] = $term->slug;
 			$t['value'] = join(', ', $values);
+			$t['taxonomy'] = true;
 
 			$form_fields[$taxonomy] = $t;
 		}
@@ -1363,6 +1366,7 @@
 			continue;
 		}
 
+		$readonly      = ! $user_can_edit && ! empty( $field['taxonomy'] ) ? " readonly='readonly' " : '';
 		$required      = $field['required'] ? '<span class="alignright"><abbr title="required" class="required">*</abbr></span>' : '';
 		$aria_required = $field['required'] ? " aria-required='true' " : '';
 		$class  = 'compat-field-' . $id;
@@ -1381,7 +1385,7 @@
 			}
 			$item .= "<textarea id='$id_attr' name='$name' $aria_required>" . $field['value'] . '</textarea>';
 		} else {
-			$item .= "<input type='text' class='text' id='$id_attr' name='$name' value='" . esc_attr( $field['value'] ) . "' $aria_required />";
+			$item .= "<input type='text' class='text' id='$id_attr' name='$name' value='" . esc_attr( $field['value'] ) . "' $readonly $aria_required />";
 		}
 		if ( !empty( $field['helps'] ) )
 			$item .= "<p class='help'>" . join( "</p>\n<p class='help'>", array_unique( (array) $field['helps'] ) ) . '</p>';
